1 Create a corpus with metadata

First, we will read in the corpus and metadata to create a table. This table will represent each text as one row, and will have multiple columns including the filename, discipline, journal title, year of publication, article title, author names, and complete text of the document.

#Load relevant R packages
library(tidyverse)
package ‘tidyverse’ was built under R version 3.6.2package ‘ggplot2’ was built under R version 3.6.2package ‘tibble’ was built under R version 3.6.2package ‘tidyr’ was built under R version 3.6.2package ‘readr’ was built under R version 3.6.2package ‘purrr’ was built under R version 3.6.2package ‘dplyr’ was built under R version 3.6.2package ‘forcats’ was built under R version 3.6.2
library(quanteda)
undefined subclass "numericVector" of class "Mnumeric"; definition not updated
library(MASS)

#Load in corpus metadata to a table
metadata <- readxl::read_excel("corpus_metadata.xlsx")

#Create a function to read in all of the texts into a table
readtext_lite <- function(paths) {
  # Get a vector of the file basenames
  doc_ids <- basename(paths)
  # Create a vector collapsing each text file into one element in a character vector
  texts <- vapply(paths, function(i) paste(readLines(i), collapse = "\n"), 
                  FUN.VALUE = character(1))
  text_df <- data.frame(doc_id = doc_ids, text = texts, stringsAsFactors = FALSE)
  return(text_df)
}
doc_df <- readtext_lite(metadata$Filename)

#Create a corpus from the data frame and attach metadata
full_corpus <- corpus(doc_df, docid_field="doc_id", text_field="text")
docvars(full_corpus) <- metadata

2 Count function words

Next, we create normalized counts of function words in each text. The list of function words used here is drawn from Longman’s Grammar (1999).

#Count tokens in each text
corpus_tokens <- tokens(full_corpus, include_docvars=TRUE, remove_punct = TRUE,
                        remove_numbers = FALSE, remove_symbols = TRUE, what = "word")

#To account for phrasal function words, combine phrases together with underscores
multiword_expressions <- readLines("phrasal_fxn_words.txt")
corpus_tokens <- tokens_compound(corpus_tokens, pattern = phrase(multiword_expressions))
rawtokens_dfm <- dfm(corpus_tokens)

#Create vector of function words
fxn_words = readLines("fxn_words.txt")

#Select only function words
fxnword_rawtokens_dfm <-dfm_select(rawtokens_dfm, pattern = fxn_words, selection = "keep")

#Normalize token counts per 10,000 words
fxnword_normalized_dfm <- 10000*(dfm_weight(fxnword_rawtokens_dfm, scheme = "prop"))

Here is a small sample of what we have created. Below is a table with a text on each row, and the normalized (by 10,000) counts of a few function words.

Document-feature matrix of: 5 documents, 4 features (0.0% sparse).
5 x 4 sparse Matrix of class "dfm"
                    features
docs                      are       in        a       of
  cs_cvpr_2017_1.txt 157.3346 421.1013 578.4359 527.5335
  cs_cvpr_2017_2.txt 183.4352 683.7132 311.2840 767.0928
  cs_cvpr_2017_3.txt 183.5915 499.1394 395.8692 510.6139
  cs_cvpr_2017_4.txt 329.0247 458.2844 511.1633 652.1739
  cs_cvpr_2017_5.txt 383.6572 662.6806 443.4479 642.7504

3 Exploratory data analysis

Before jumping into more complicated stylometry analyses, we’re first going to do some exploratory data analysis. In this section, we’ll perform some more common text analyses to start getting a feel for how our data is distributed and what kinds of trends and patterns are showing up.

3.1 Word counts

All of the texts in this corpus are academic articles, so we might expect them to be reasonably similar in terms of length. When plotting the lengths, we find that most tend to center around 10,000 words, but there are some very long outliers.

tokencount <- ntoken(rawtokens_dfm)
#Calculate binwidth with the Freedman–Diaconis rule
binwidth_tokens <- 2 * IQR(tokencount) / length(tokencount)^(1 / 3)

#create a dataframe with token counts and disciplines
fxnword_normalized_df <- convert(fxnword_normalized_dfm, to = "data.frame")
fxnword_normalized_df$wordcount <- tokencount
fxnword_normalized_df$discipline <- metadata$Discipline
#plot histogram of lengths
ggplot(fxnword_normalized_df, aes(x = wordcount)) + geom_histogram(binwidth = binwidth_tokens) +ylab("Number of papers") + xlab("Word count")

Further investigation the very long outliers appear to be driven by the discipline of physics.

3.2 Frequencies of key function words

Preliminary data analysis showed that the following function words had large differences in z-scores between disciplines: were, how, they, as. Below are the normalized frequencies of these four words across disciplines, showing differences.

#plot the four words
were_plot <- ggplot(data=fxnword_normalized_df,mapping=aes(x=reorder(discipline,-were, FUN = median), y=were)) + geom_boxplot(color="blue",fill="white") + theme_bw() + theme(text = element_text(size=6), axis.text.x = element_text(angle = 30, hjust = 1)) + xlab("Discipline") + ylab("were")

how_plot <- ggplot(data=fxnword_normalized_df,mapping=aes(x=reorder(discipline,-how, FUN = median), y=how)) + geom_boxplot(color="blue",fill="white")+ theme_bw() + theme(text = element_text(size=6), axis.text.x = element_text(angle = 30, hjust = 1)) + xlab("Discipline") + ylab("how")

they_plot <- ggplot(data=fxnword_normalized_df,mapping=aes(x=reorder(discipline,-they, FUN = median), y=they)) + geom_boxplot(color="blue",fill="white")+ theme_bw() + theme(text = element_text(size=6), axis.text.x = element_text(angle = 30, hjust = 1)) + xlab("Discipline") + ylab("they")

as_plot <- ggplot(data=fxnword_normalized_df,mapping=aes(x=reorder(discipline,-as, FUN = median), y=as)) + geom_boxplot(color="blue",fill="white")+ theme_bw() + theme(text = element_text(size=6), axis.text.x = element_text(angle = 30, hjust = 1)) + xlab("Discipline") + ylab("as")

#arrange into a visual
gridExtra::grid.arrange(were_plot, how_plot, they_plot, as_plot)

3.3 Keyness and effect size

The tables below identify 5 words for each discipline that are key in that discipline (compared to all of the other disciplines combined), and the effect size of those words. These tables are sorted by keyness values. A high keyness value indicates that there is a lot of evidence for difference in frequencies of that word between disciplines, while a high effect size indicates that the difference is quite large. Here, the keyness is calculated using log-likelihood and the effect size calculated using Hardie’s log ratio.

#create dfm grouped by discipline
keyness_dfm <- dfm_group(rawtokens_dfm, groups="Disc_short")
discipline_vector <- unique(metadata$Disc_short)
#define function for calculating effect size using Hardie's log ratio
effect_size <- function (n_target, n_reference) {
  total_a <- sum(n_target)
  total_b <- sum(n_reference)
  percent_a <- ifelse(n_target == 0, 0.5 / total_a, n_target/total_a)
  percent_b <- ifelse(n_reference == 0, 0.5 / total_b, n_reference/total_b)
  ratio <- log2(percent_a / percent_b)
  return(ratio)
}
#create list to store values in and data frame to print
keywords <- list()
keyword_table <- data.frame()
#loop through disciplines and store values in keywords list
#you can now access any discipline's keyness and effect size values with keywords[['[disc]']]. Ex: keywords[['cs']]
for (i in 1:length(discipline_vector)) {
  #get keywords
  keywords[[discipline_vector[i]]] <- textstat_keyness(keyness_dfm, 
                                                     target=discipline_vector[i], 
                                                     measure = "lr")
  #add effect size
  keywords[[discipline_vector[i]]] <- keywords[[discipline_vector[i]]] %>% 
    mutate(., effect = effect_size(n_target, n_reference))
  #take away target and reference counts
  pr <- dplyr::select(as.data.frame(keywords[[discipline_vector[i]]]), -n_target, -n_reference)
  #rename columns
  names(pr)[2] <- 'keyness'
  names(pr)[3] <- 'p-value'
  names(pr)[4] <- 'effect size'
  #append to table for printing & save discipline name
  keyword_table <- rbind(keyword_table, format(head(pr,n=5), nsmall=3, digits=3))
}
#print tables
library(knitr)
library(kableExtra)
kable(keyword_table, caption = "Keyness and Effect Size") %>%
  kable_styling("striped", full_width = F) %>%
  pack_rows(discipline_vector[[1]], 1,5) %>%
  pack_rows(discipline_vector[[2]], 6,10) %>%
  pack_rows(discipline_vector[[3]], 11,15) %>%
  pack_rows(discipline_vector[[4]], 16, 20) %>%
  pack_rows(discipline_vector[[5]], 21,25) %>%
  pack_rows(discipline_vector[[6]], 26, 30) %>%
  pack_rows(discipline_vector[[7]], 31,35) %>%
  pack_rows(discipline_vector[[8]], 36, 40) %>%
  pack_rows(discipline_vector[[9]], 41,45) %>%
  pack_rows(discipline_vector[[10]], 46, 50) %>%
  pack_rows(discipline_vector[[11]], 51,55) %>%
  pack_rows(discipline_vector[[12]], 56, 60) %>%
  pack_rows(discipline_vector[[13]], 61,65)
Keyness and Effect Size
feature keyness p-value effect size
cs
1 algorithm 8471.886 0.000 5.011
2 s 8317.811 0.000 2.842
3 v 6973.859 0.000 3.443
4 1 6705.538 0.000 1.520
5 we 6579.818 0.000 1.416
perf
11 dance 16781.315 0.000 7.781
21 theatre 12505.260 0.000 9.808
31 ballet 6446.625 0.000 9.350
41 dancers 5313.173 0.000 9.137
51 performance 5253.940 0.000 3.008
cheme
12 reaction 11541.052 0.000 6.457
22 co 8537.453 0.000 7.129
32 tio2 8329.074 0.000 13.039
42 catalyst 8130.326 0.000 8.530
52 catalysts 8063.386 0.000 10.601
ling
13 languages 6614.868 0.000 5.202
23 speakers 5895.676 0.000 5.761
33 english 5514.495 0.000 3.630
43 vowel 5461.015 0.000 11.194
53 verb 4875.104 0.000 7.472
ed
14 teachers 27742.143 0.000 7.025
24 students 19570.715 0.000 5.085
34 school 12642.213 0.000 4.486
44 teacher 11054.757 0.000 5.786
54 children 10595.175 0.000 3.833
bio
15 cells 40573.610 0.000 7.962
25 et 12111.695 0.000 2.647
35 al 11948.197 0.000 2.622
45 cell 11105.182 0.000 5.826
55 figure 10242.081 0.000 2.938
phil
16 that 13281.927 0.000 1.211
26 is 12517.445 0.000 1.172
36 it 7648.853 0.000 1.465
46 if 6404.190 0.000 1.977
56 belief 5154.391 0.000 4.465
phys
17 ¼ 31406.271 0.000 9.343
27 þ 12035.933 0.000 8.039
37 energy 6992.521 0.000 3.963
47 et 6299.804 0.000 1.805
57 al 6294.149 0.000 1.795
lit
18 literary 8200.181 0.000 7.032
28 his 8034.616 0.000 2.454
38 narrative 4757.758 0.000 4.303
48 he 3630.001 0.000 1.922
58 poem 3443.847 0.000 7.202
soc
19 social 5372.210 0.000 2.329
29 income 5186.595 0.000 4.472
39 women 4698.982 0.000 3.210
49 mothers 4088.584 0.000 5.055
59 racial 3731.433 0.000 3.495
stats
110 x 35224.322 0.000 3.987
210 1 31579.844 0.000 2.607
310 n 23528.688 0.000 3.424
410 0 13546.241 0.000 2.869
510 k 10535.447 0.000 3.220
polsci
111 party 6912.617 0.000 4.739
211 political 6527.650 0.000 2.929
311 parties 5588.803 0.000 5.511
411 democratic 4692.951 0.000 5.107
511 democracy 4055.320 0.000 5.483
hist
112 had 9317.536 0.000 2.666
212 was 7121.690 0.000 1.480
312 british 4781.092 0.000 4.800
412 he 4091.505 0.000 1.888
512 his 3851.584 0.000 1.737

4 Stylometry

In this section, we are interested in how papers cluster together based on the “distances” between them, and what particular words are driving these clusters.

There are many different ways to calculate the distances between texts. Some common distance measurements include Euclidean, Delta, Manhattan, Argamon’s, Canberra, Wurzburg, Cosine, and Min-Max. The basic idea behind all of these is to represent how similar two texts are, based on how similar their distributions of function words are. Thus, texts with very similar distributions of function words get a lower distance. The methods vary in their precise algorithm to calculate this distance.

Each graph below uses a different distance measurement. Based on these distances, the dendrograms below are created using agglomerative hierarchical clustering. Each node at the right represents one text, color-coded by discipline. It is not important (or feasible) here to see all of the text names, but it is interesting to see which distance algorithm produces the best clustering of papers (in other words, which graph shows the colors most tightly grouped together). It appears that Manhattan and Delta are doing a fairly good job, while Euclidean and Wurzburg seem a little messier.

#create data frame for analysis
stylo_df<-dplyr::select(fxnword_normalized_df, -wordcount, -discipline) %>% data.frame(., row.names=1)

#run results w various distance measures
stylo_euclidean_results <- stylo::stylo(gui=FALSE, frequencies = stylo_df, mfw.min = 240, mfw.max=240, plot.custom.height = 13, plot.font.size = 1.8, distance.measure='euclidean', display.on.screen = FALSE, write.jpg.file = TRUE)

stylo_delta_results <- stylo::stylo(gui=FALSE, frequencies = stylo_df, mfw.min = 240, mfw.max=240, plot.custom.height = 13, plot.font.size = 1.8, distance.measure='delta', display.on.screen = FALSE, write.jpg.file = TRUE, write.jpg.file = TRUE)

stylo_manhattan_results <- stylo::stylo(gui=FALSE, frequencies = stylo_df, mfw.min = 240, mfw.max=240, plot.custom.height = 13, plot.font.size = 1.8, distance.measure='manhattan', display.on.screen = FALSE, write.jpg.file = TRUE)

stylo_argamon_results <- stylo::stylo(gui=FALSE, frequencies = stylo_df, mfw.min = 240, mfw.max=240, plot.custom.height = 13, plot.font.size = 1.8, distance.measure='argamon', display.on.screen = FALSE, write.jpg.file = TRUE)

stylo_canberra_results <- stylo::stylo(gui=FALSE, frequencies = stylo_df, mfw.min = 240, mfw.max=240, plot.custom.height = 13, plot.font.size = 1.8, distance.measure='canberra', display.on.screen = FALSE, write.jpg.file = TRUE)

stylo_wurzburg_results <- stylo::stylo(gui=FALSE, frequencies = stylo_df, mfw.min = 240, mfw.max=240, plot.custom.height = 13, plot.font.size = 1.8, distance.measure='wurzburg', display.on.screen = FALSE, write.jpg.file = TRUE)

stylo_cosine_results <- stylo::stylo(gui=FALSE, frequencies = stylo_df, mfw.min = 240, mfw.max=240, plot.custom.height = 13, plot.font.size = 1.8, distance.measure='cosine', display.on.screen = FALSE, write.jpg.file = TRUE)

stylo_minmax_results <- stylo::stylo(gui=FALSE, frequencies = stylo_df, mfw.min = 240, mfw.max=240, plot.custom.height = 13, plot.font.size = 1.8, distance.measure='minmax', display.on.screen = FALSE, write.jpg.file = TRUE)

In the keyness and effect size tables, it became apparent that pronouns were playing a large role in disciplinary discourse. Because pronoun use might be intuitive in some cases (for example, history may use a lot of “he” to talk about historical male figures that have been historically overrrepresented in comparison to women), it may be interesting to explore disciplinary differences when pronouns are not included in the function words analyzed. The graphs below repeat the analysis done before, but with pronouns left out.

Delta appears to be one of the strongest out of each measurement tested, and also has a lot of previous research around it to suggest its strength in authorship attribution (note that Manhattan is also especially strong, and it may be worth exploring some of the reasons for this). The figures below show both cluster analyses using the Delta measurement, both with and without pronouns, for comparison. There are not major differences between the two, though without pronouns appears to be slightly more accurate in grouping disciplines. The clusters themselves are also somewhat different.

Another way to visualize the distances here is through techniques drawn from network analysis, as laid out in Eder (2017). When dendrograms are created from the bottom-up, the two nodes with the smallest distance are connected, which disregards any information about which node was 2nd or 3rd closest. This information might also be useful for helping to see which texts are most closely related. Delta distances (without pronouns) are visualized below using Gephi (a data visualization program) with the ForceAtlas2 setting, which helps to better visualize clusters. Ultimately, this visualization allows us to more easily see clusters, and which clusters are close to each other, of texts.

5 Chapter analyses

5.1 Case study: Part 1

Part 1 of the case study will focus on explaining the difference in function word usage between the humanities and the sciences. This is a split that we see both in the network analysis visualization, and dendrograms based on Delta distance above.

In order to do this analysis, we first identify what function words seem to contribute most to this split. In other words, which function words are driving the largest distance between humanities and science texts? Then for these function words, we add information about p-values, effect sizes, and keyness. The table below shows, for each function word, the total of its usage (in terms of z-scores) in both the humanities and sciences. The difference column simply subtracts the two, and the table is ranked by this column.

#create master df for storing data
distance_pieces_df <- matrix(0, nrow=209, 
                             ncol=nrow(stylo_delta_results_nopronouns$table.with.all.zscores)^2)

#create column names as a vector
column_names <- outer(rownames(stylo_delta_results_nopronouns$table.with.all.zscores),
                      rownames(stylo_delta_results_nopronouns$table.with.all.zscores),
                      "paste",
                      sep = "XXX")
column_names <- as.vector(column_names)

#calculate distances between every text and add to master df
for (fxnword in 1:209) {
  rowvalues <- outer(stylo_delta_results_nopronouns$table.with.all.zscores[,fxnword],
                     stylo_delta_results_nopronouns$table.with.all.zscores[,fxnword],
                     "-")
  attr(rowvalues, "dim") <- prod(dim(rowvalues))
  
  distance_pieces_df[fxnword,] <- rowvalues
  print(paste("progress is ",fxnword,"/209",sep=""))
}

distance_pieces_df <- as.data.frame(abs(distance_pieces_df))
colnames(distance_pieces_df) <- column_names
distance_pieces_df["Delta_distance",] <- colSums(distance_pieces_df)

#remove duplicated columns
distance_pieces_ids<-duplicated(as.list(distance_pieces_df))
delete<-which(distance_pieces_ids)
distance_pieces_df_v2 <- distance_pieces_df[,-c(delete)]
distance_pieces_df_v2 <- distance_pieces_df_v2[,-1]
#keep only comparisons from entire comparison set that are between humanities and sciences
ch1_comparisons<-c()
for (text in 1:ncol(distance_pieces_df_v2)){
  text2 <- substring(stringr::str_extract(colnames(distance_pieces_df_v2)[text],"XXX.*$"),4)
  text1 <- colnames(distance_pieces_df_v2)[text]
  if (startsWith(text1,"bio") || startsWith(text1,"cs")||
      startsWith(text1,"phys")|| startsWith(text1,"cheme")|| 
      startsWith(text1,"stats")){
    text1_type<-"sciences"
  }
  else{
    text1_type<-"humanities"
  }
  if (startsWith(text2,"bio") || startsWith(text2,"cs")|| 
      startsWith(text2,"phys")|| startsWith(text2,"cheme")|| 
      startsWith(text2,"stats")){
    text2_type<-"sciences"
  }
  else{
    text2_type<-"humanities"
  }
  if (text1_type != text2_type){
    ch1_comparisons<-c(ch1_comparisons,text)
    print(text1)
  }
}

distance_pieces_ch1 <- distance_pieces_df_v2[,ch1_comparisons]

#add up rows to create a total column
distance_pieces_ch1$total_distance<-rowSums(distance_pieces_ch1)
#sort whole df by the total_distance column
distance_pieces_ch1 <- distance_pieces_ch1[order(distance_pieces_ch1$total_distance, decreasing=TRUE),]

#create df for comparing
ch1_delta_df<-data.frame(distance_pieces_ch1$total_distance)
rownames(ch1_delta_df)<-rownames(distance_pieces_ch1)

#clean up error??
ch1_rownames <- rownames(ch1_delta_df)
ch1_rownames<-stringr::str_replace(ch1_rownames, "\\.", "")
rownames(ch1_delta_df)<-ch1_rownames

Finally, the tables created below show each keyword in context for every text. Samples are shown below. A particular keyword’s usage in either the humanities or sciences can be accessed with sciences_kwic[[‘the’]]. A particular keyword’s usage in a particular paper can be accessed with sciences_kwic[[‘the’]][sciences_kwic[[‘the’]]$docname == ‘cs_cvpr_2017_1.txt’,].

print(head(sciences_kwic[['the']][sciences_kwic[['the']]$docname == 'cs_cvpr_2017_1.txt',]))

print(head(humanities_kwic[['the']][humanities_kwic[['the']]$docname == 'perf_tdr_2017_1.txt',]))

5.2 Case study: Part 2

The table preview below shows which function words contribute to the spread within the sciences and humanities, respectively. In particular, the table below shows which words contribute most to the distance between computer science and cell & molecular biology, and philosophy and history. It also includes averages for each discipline on each function word, as well as p-values, effect sizes, and log-likelihood values.

#sciences
#keep only comparisons between cs and bio
ch2_comparisons<-c()
for (text in 1:ncol(distance_pieces_df_v2)){
  text2 <- substring(stringr::str_extract(colnames(distance_pieces_df_v2)[text],"XXX.*$"),4)
  text1 <- colnames(distance_pieces_df_v2)[text]
  if (startsWith(text1,"bio")){
    text1_type<-"bio"
  } else if (startsWith(text1,"cs")){
    text1_type<-"cs"
  } else {
    text1_type<-"other"
  } 
  if (startsWith(text2,"bio")){
    text2_type<-"bio"
  } else if (startsWith(text2,"cs")){
    text2_type<-"cs"
  } else {
    text2_type<-"other"
  } 
  if (text1_type == "bio" && text2_type == "cs" || text1_type == "cs" && text2_type =="bio"){
    ch2_comparisons<-c(ch2_comparisons,text)
    print(text1)
  }
}

distance_pieces_sciences_ch2 <- distance_pieces_df_v2[,ch2_comparisons]

#add up rows to create a total column
distance_pieces_sciences_ch2$total_distance<-rowSums(distance_pieces_sciences_ch2)
#sort whole df by the total_distance column
distance_pieces_sciences_ch2 <- distance_pieces_sciences_ch2[order(distance_pieces_sciences_ch2$total_distance, decreasing=TRUE),]

#create df for comparing
ch2_sciences_df<-data.frame(distance_pieces_sciences_ch2$total_distance)
rownames(ch2_sciences_df)<-rownames(distance_pieces_sciences_ch2)

#humanities
#keep only comparisons between phil & hist
ch2_comparisons_hum<-c()
for (text in 1:ncol(distance_pieces_df_v2)){
  text2 <- substring(stringr::str_extract(colnames(distance_pieces_df_v2)[text],"XXX.*$"),4)
  text1 <- colnames(distance_pieces_df_v2)[text]
  if (startsWith(text1,"hist")){
    text1_type<-"hist"
  } else if (startsWith(text1,"phil")){
    text1_type<-"phil"
  } else {
    text1_type<-"other"
  } 
  if (startsWith(text2,"hist")){
    text2_type<-"hist"
  } else if (startsWith(text2,"phil")){
    text2_type<-"phil"
  } else {
    text2_type<-"other"
  } 
  if (text1_type == "hist" && text2_type == "phil" || text1_type == "phil" && text2_type =="hist"){
    ch2_comparisons_hum<-c(ch2_comparisons_hum,text)
  }
}

distance_pieces_hum_ch2 <- distance_pieces_df_v2[,ch2_comparisons_hum]

#add up rows to create a total column
distance_pieces_hum_ch2$total_distance<-rowSums(distance_pieces_hum_ch2)
#sort whole df by the total_distance column
distance_pieces_hum_ch2 <- distance_pieces_hum_ch2[order(distance_pieces_hum_ch2$total_distance, decreasing=TRUE),]

#create df for comparing
ch2_hum_df<-data.frame(distance_pieces_hum_ch2$total_distance)
rownames(ch2_hum_df)<-rownames(distance_pieces_hum_ch2)
print(head(ch2_sciences_df))

print(head(ch2_hum_df))

5.3 Case study: Part 3

In order to determine what contributes to the “spread” within a discipline, we can isolate which words contribute to the most total distance between papers in the same discipline. First we’ll calculate the distance contributions of each word. Then, we’ll also add info about median frequencies for each discipline on each function word, as well as standard deviation, total counts, and highs and lows. The tables below show data on this for history and computer science.

#add medians, highs, lows
#create token objects
##Count tokens in each text
ch3cs_tokens <- tokens(ch2_cs_corpus, include_docvars=TRUE, remove_punct = TRUE,
                        remove_numbers = FALSE, remove_symbols = TRUE, what = "word")
##To account for phrasal function words, combine phrases together with underscores
ch3cs_tokens <- tokens_compound(ch3cs_tokens, pattern = phrase(multiword_expressions))
ch3cs_rawtokens_dfm <- dfm(ch3cs_tokens)
##Count tokens in each text
ch3hist_tokens <- tokens(ch2_hist_corpus, include_docvars=TRUE, remove_punct = TRUE,
                        remove_numbers = FALSE, remove_symbols = TRUE, what = "word")
##To account for phrasal function words, combine phrases together with underscores
ch3hist_tokens <- tokens_compound(ch3hist_tokens, pattern = phrase(multiword_expressions))
ch3hist_rawtokens_dfm <- dfm(ch3hist_tokens)

#get frequencies
hist_freqs_temp<-as.data.frame(dfm_weight(ch3hist_rawtokens_dfm,scheme="prop")*10000)
'as.data.frame.dfm' is deprecated.
Use 'convert(x, to = "data.frame")' instead.
See help("Deprecated")
cs_freqs_temp<-as.data.frame(dfm_weight(ch3cs_rawtokens_dfm,scheme="prop")*10000)
'as.data.frame.dfm' is deprecated.
Use 'convert(x, to = "data.frame")' instead.
See help("Deprecated")
##fix up names
names(cs_freqs_temp) <- gsub(".", "", names(cs_freqs_temp), fixed = TRUE)
names(hist_freqs_temp) <- gsub(".", "", names(hist_freqs_temp), fixed = TRUE)
cs_freqs <- cs_freqs_temp[,-1]
row.names(cs_freqs) <- cs_freqs_temp[,1]
hist_freqs <- hist_freqs_temp[,-1]
row.names(hist_freqs) <- hist_freqs_temp[,1]

##keep only fxn words
fxnwords_cs <- c(rownames(ch3_cs_df))
cs_desired_vars <- function(x) names(x) %in% fxnwords_cs
fxnwords_hist <- c(rownames(ch3_hist_df))
hist_desired_vars <- function(x) names(x) %in% fxnwords_hist
cs_freqs_fxns <- cs_freqs[,cs_desired_vars(cs_freqs)]
hist_freqs_fxns <- hist_freqs[,hist_desired_vars(hist_freqs)]
##add column for median, high, and low for each word
cs_freqs_fxns<-as.data.frame(t(cs_freqs_fxns))
hist_freqs_fxns<-as.data.frame(t(hist_freqs_fxns))
cs_freqs_fxns$median_freq = apply(cs_freqs_fxns,1,median)
hist_freqs_fxns$median_freq = apply(hist_freqs_fxns,1,median)
cs_freqs_fxns$high_freq = apply(cs_freqs_fxns,1,max)
hist_freqs_fxns$high_freq = apply(hist_freqs_fxns,1,max)
cs_freqs_fxns$low_freq = apply(cs_freqs_fxns,1,min)
hist_freqs_fxns$low_freq = apply(hist_freqs_fxns,1,min)

##attach to cs & hist dfs
ch3_cs_temp <- merge(ch3_cs_df, cs_freqs_fxns[,c("median_freq","high_freq","low_freq")], by=0, all=TRUE)
ch3_hist_temp <- merge(ch3_hist_df, hist_freqs_fxns[,c("median_freq","high_freq","low_freq")], by=0, all=TRUE)
#make rownames
ch3_cs <- ch3_cs_temp[,-1]
row.names(ch3_cs) <- ch3_cs_temp[,1]
ch3_hist <- ch3_hist_temp[,-1]
row.names(ch3_hist) <- ch3_hist_temp[,1]

#sciences
#select just function word columns
ch3cs_rawtokens_df <- data.frame(ch3cs_rawtokens_dfm)
'as.data.frame.dfm' is deprecated.
Use 'convert(x, to = "data.frame")' instead.
See help("Deprecated")
names(ch3cs_rawtokens_df) <- gsub(".", "", names(ch3cs_rawtokens_df), fixed = TRUE)
ch3cs_fnxwords_rawtokens <- ch3cs_rawtokens_df[,cs_desired_vars(ch3cs_rawtokens_df)]
row.names(ch3cs_fnxwords_rawtokens)<-row.names(ch3cs_rawtokens_df)
#add row for total count
ch3cs_fnxwords_rawtokens["N",] =colSums(ch3cs_fnxwords_rawtokens[-c(nrow(ch3cs_fnxwords_rawtokens)),])
#hum
#select just function word columns
ch3hist_rawtokens_df <- data.frame(ch3hist_rawtokens_dfm)
'as.data.frame.dfm' is deprecated.
Use 'convert(x, to = "data.frame")' instead.
See help("Deprecated")
names(ch3hist_rawtokens_df) <- gsub(".", "", names(ch3hist_rawtokens_df), fixed = TRUE)
ch3hist_fnxwords_rawtokens <- ch3hist_rawtokens_df[,hist_desired_vars(ch3hist_rawtokens_df)]
row.names(ch3hist_fnxwords_rawtokens)<-row.names(ch3hist_rawtokens_df)
#add row for total count
ch3hist_fnxwords_rawtokens["N",] =colSums(ch3hist_fnxwords_rawtokens[-c(nrow(ch3hist_fnxwords_rawtokens)),])
#add N data to discipline dfs
ch3cs_fnxwords_rawtokens <- as.data.frame(t(ch3cs_fnxwords_rawtokens))
ch3hist_fnxwords_rawtokens <- as.data.frame(t(ch3hist_fnxwords_rawtokens))
ch3_cs$N=ch3cs_fnxwords_rawtokens$N[match(rownames(ch3_cs),rownames(ch3cs_fnxwords_rawtokens))]
ch3_hist$N=ch3hist_fnxwords_rawtokens$N[match(rownames(ch3_hist),rownames(ch3hist_fnxwords_rawtokens))]

#get and add standard deviation
cs_freqs["st_dev",]=matrixStats::colSds(as.matrix(cs_freqs))
hist_freqs["st_dev",]=matrixStats::colSds(as.matrix(hist_freqs))
cs_freqs = as.data.frame(t(cs_freqs))
hist_freqs = as.data.frame(t(hist_freqs))
ch3_cs$st_dev = cs_freqs$st_dev[match(rownames(ch3_cs),rownames(cs_freqs))]
ch3_hist$st_dev=hist_freqs$st_dev[match(rownames(ch3_hist),rownames(hist_freqs))]

#print heads of results
rownametocut<-c("Delta_distance")
print_cs_df<-ch3_cs[!(row.names(ch3_cs) %in% rownametocut),]
print_hist_df<-ch3_hist[!(row.names(ch3_hist) %in% rownametocut),]
head(print_cs_df[order(print_cs_df$Delta_distance,decreasing=TRUE),],n=8)
head(print_hist_df[order(print_hist_df$Delta_distance,decreasing=TRUE),],n=8)

Now that we have these words, let’s check if any of them are correlated. That is, are texts that are low in one of these words also low in another? Or low in one often high in another? This will help to identify any groups that there might be in the data. Here are the correlation tables for the top function words in history and computer science (1 indicates a perfect correlation, and 0 no correlation).

cor(ch3_hist_short[,unlist(lapply(ch3_hist_short, is.numeric))])
               had    despite     against     anyone       many     such_as     though
had     1.00000000 0.15574888  0.18849685 0.27826487 0.11407400  0.05804479 0.01822847
despite 0.15574888 1.00000000  0.11607579 0.07970601 0.14595186  0.16613874 0.21878957
against 0.18849685 0.11607579  1.00000000 0.15565175 0.03122565 -0.01548640 0.01687798
anyone  0.27826487 0.07970601  0.15565175 1.00000000 0.07956208  0.02607009 0.18414853
many    0.11407400 0.14595186  0.03122565 0.07956208 1.00000000  0.10130478 0.16280894
such_as 0.05804479 0.16613874 -0.01548640 0.02607009 0.10130478  1.00000000 0.13640176
though  0.01822847 0.21878957  0.01687798 0.18414853 0.16280894  0.13640176 1.00000000
cor(ch3_cs_short[,unlist(lapply(ch3_cs_short, is.numeric))])
                 every   such_that         our       next        each        which     instead
every      1.000000000  0.49118922  0.13966804 0.21261501 -0.05537442  0.002988592 -0.03637981
such_that  0.491189216  1.00000000  0.02481091 0.29280608 -0.05494849 -0.049153043  0.04657911
our        0.139668040  0.02481091  1.00000000 0.21787678 -0.10090014  0.016597781  0.28561798
next       0.212615010  0.29280608  0.21787678 1.00000000  0.06189560  0.174193206  0.04142731
each      -0.055374415 -0.05494849 -0.10090014 0.06189560  1.00000000  0.243865688  0.13674084
which      0.002988592 -0.04915304  0.01659778 0.17419321  0.24386569  1.000000000  0.12695988
instead   -0.036379815  0.04657911  0.28561798 0.04142731  0.13674084  0.126959885  1.00000000
LS0tCnRpdGxlOiAiRGlzc2VydGF0aW9uIEFuYWx5c2lzIgphdXRob3I6ICJIYW5uYWggUmluZ2xlciIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgaHRtbF9ub3RlYm9vazoKICAgIGhpZ2hsaWdodDoga2F0ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBwYXBlcgogICAgdG9jOiB5ZXMKLS0tCiMgQ3JlYXRlIGEgY29ycHVzIHdpdGggbWV0YWRhdGEKRmlyc3QsIHdlIHdpbGwgcmVhZCBpbiB0aGUgY29ycHVzIGFuZCBtZXRhZGF0YSB0byBjcmVhdGUgYSB0YWJsZS4gVGhpcyB0YWJsZSB3aWxsIHJlcHJlc2VudCBlYWNoIHRleHQgYXMgb25lIHJvdywgYW5kIHdpbGwgaGF2ZSBtdWx0aXBsZSBjb2x1bW5zIGluY2x1ZGluZyB0aGUgZmlsZW5hbWUsIGRpc2NpcGxpbmUsIGpvdXJuYWwgdGl0bGUsIHllYXIgb2YgcHVibGljYXRpb24sIGFydGljbGUgdGl0bGUsIGF1dGhvciBuYW1lcywgYW5kIGNvbXBsZXRlIHRleHQgb2YgdGhlIGRvY3VtZW50LgoKYGBge3IgY3JlYXRlIGNvcnB1cywgbWVzc2FnZT1GQUxTRX0KI0xvYWQgcmVsZXZhbnQgUiBwYWNrYWdlcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShxdWFudGVkYSkKbGlicmFyeShNQVNTKQoKI0xvYWQgaW4gY29ycHVzIG1ldGFkYXRhIHRvIGEgdGFibGUKbWV0YWRhdGEgPC0gcmVhZHhsOjpyZWFkX2V4Y2VsKCJjb3JwdXNfbWV0YWRhdGEueGxzeCIpCgojQ3JlYXRlIGEgZnVuY3Rpb24gdG8gcmVhZCBpbiBhbGwgb2YgdGhlIHRleHRzIGludG8gYSB0YWJsZQpyZWFkdGV4dF9saXRlIDwtIGZ1bmN0aW9uKHBhdGhzKSB7CiAgIyBHZXQgYSB2ZWN0b3Igb2YgdGhlIGZpbGUgYmFzZW5hbWVzCiAgZG9jX2lkcyA8LSBiYXNlbmFtZShwYXRocykKICAjIENyZWF0ZSBhIHZlY3RvciBjb2xsYXBzaW5nIGVhY2ggdGV4dCBmaWxlIGludG8gb25lIGVsZW1lbnQgaW4gYSBjaGFyYWN0ZXIgdmVjdG9yCiAgdGV4dHMgPC0gdmFwcGx5KHBhdGhzLCBmdW5jdGlvbihpKSBwYXN0ZShyZWFkTGluZXMoaSksIGNvbGxhcHNlID0gIlxuIiksIAogICAgICAgICAgICAgICAgICBGVU4uVkFMVUUgPSBjaGFyYWN0ZXIoMSkpCiAgdGV4dF9kZiA8LSBkYXRhLmZyYW1lKGRvY19pZCA9IGRvY19pZHMsIHRleHQgPSB0ZXh0cywgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQogIHJldHVybih0ZXh0X2RmKQp9CmRvY19kZiA8LSByZWFkdGV4dF9saXRlKG1ldGFkYXRhJEZpbGVuYW1lKQoKI0NyZWF0ZSBhIGNvcnB1cyBmcm9tIHRoZSBkYXRhIGZyYW1lIGFuZCBhdHRhY2ggbWV0YWRhdGEKZnVsbF9jb3JwdXMgPC0gY29ycHVzKGRvY19kZiwgZG9jaWRfZmllbGQ9ImRvY19pZCIsIHRleHRfZmllbGQ9InRleHQiKQpkb2N2YXJzKGZ1bGxfY29ycHVzKSA8LSBtZXRhZGF0YQpgYGAKCiMgQ291bnQgZnVuY3Rpb24gd29yZHMKTmV4dCwgd2UgY3JlYXRlIG5vcm1hbGl6ZWQgY291bnRzIG9mIGZ1bmN0aW9uIHdvcmRzIGluIGVhY2ggdGV4dC4gVGhlIGxpc3Qgb2YgZnVuY3Rpb24gd29yZHMgdXNlZCBoZXJlIGlzIGRyYXduIGZyb20gX0xvbmdtYW4ncyBHcmFtbWFyXyAoMTk5OSkuCgpgYGB7ciBjb3VudCBmdW5jdGlvbiB3b3JkcywgbWVzc2FnZSA9IEZBTFNFfQojQ291bnQgdG9rZW5zIGluIGVhY2ggdGV4dApjb3JwdXNfdG9rZW5zIDwtIHRva2VucyhmdWxsX2NvcnB1cywgaW5jbHVkZV9kb2N2YXJzPVRSVUUsIHJlbW92ZV9wdW5jdCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZV9udW1iZXJzID0gRkFMU0UsIHJlbW92ZV9zeW1ib2xzID0gVFJVRSwgd2hhdCA9ICJ3b3JkIikKCiNUbyBhY2NvdW50IGZvciBwaHJhc2FsIGZ1bmN0aW9uIHdvcmRzLCBjb21iaW5lIHBocmFzZXMgdG9nZXRoZXIgd2l0aCB1bmRlcnNjb3JlcwptdWx0aXdvcmRfZXhwcmVzc2lvbnMgPC0gcmVhZExpbmVzKCJwaHJhc2FsX2Z4bl93b3Jkcy50eHQiKQpjb3JwdXNfdG9rZW5zIDwtIHRva2Vuc19jb21wb3VuZChjb3JwdXNfdG9rZW5zLCBwYXR0ZXJuID0gcGhyYXNlKG11bHRpd29yZF9leHByZXNzaW9ucykpCnJhd3Rva2Vuc19kZm0gPC0gZGZtKGNvcnB1c190b2tlbnMpCgojQ3JlYXRlIHZlY3RvciBvZiBmdW5jdGlvbiB3b3JkcwpmeG5fd29yZHMgPSByZWFkTGluZXMoImZ4bl93b3Jkcy50eHQiKQoKI1NlbGVjdCBvbmx5IGZ1bmN0aW9uIHdvcmRzCmZ4bndvcmRfcmF3dG9rZW5zX2RmbSA8LWRmbV9zZWxlY3QocmF3dG9rZW5zX2RmbSwgcGF0dGVybiA9IGZ4bl93b3Jkcywgc2VsZWN0aW9uID0gImtlZXAiKQoKI05vcm1hbGl6ZSB0b2tlbiBjb3VudHMgcGVyIDEwLDAwMCB3b3JkcwpmeG53b3JkX25vcm1hbGl6ZWRfZGZtIDwtIDEwMDAwKihkZm1fd2VpZ2h0KGZ4bndvcmRfcmF3dG9rZW5zX2RmbSwgc2NoZW1lID0gInByb3AiKSkKCmBgYAoKSGVyZSBpcyBhIHNtYWxsIHNhbXBsZSBvZiB3aGF0IHdlIGhhdmUgY3JlYXRlZC4gQmVsb3cgaXMgYSB0YWJsZSB3aXRoIGEgdGV4dCBvbiBlYWNoIHJvdywgYW5kIHRoZSBub3JtYWxpemVkIChieSAxMCwwMDApIGNvdW50cyBvZiBhIGZldyBmdW5jdGlvbiB3b3Jkcy4KCmBgYHtyIHZpZXcgZnJlcXVlbmN5IHRhYmxlLCBlY2hvPUZBTFNFfQpwcmludChoZWFkKGZ4bndvcmRfbm9ybWFsaXplZF9kZm0sNSxuZj00KSkKYGBgCgojIEV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMKQmVmb3JlIGp1bXBpbmcgaW50byBtb3JlIGNvbXBsaWNhdGVkIHN0eWxvbWV0cnkgYW5hbHlzZXMsIHdlJ3JlIGZpcnN0IGdvaW5nIHRvIGRvIHNvbWUgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcy4gSW4gdGhpcyBzZWN0aW9uLCB3ZSdsbCBwZXJmb3JtIHNvbWUgbW9yZSBjb21tb24gdGV4dCBhbmFseXNlcyB0byBzdGFydCBnZXR0aW5nIGEgZmVlbCBmb3IgaG93IG91ciBkYXRhIGlzIGRpc3RyaWJ1dGVkIGFuZCB3aGF0IGtpbmRzIG9mIHRyZW5kcyBhbmQgcGF0dGVybnMgYXJlIHNob3dpbmcgdXAuCgojIyBXb3JkIGNvdW50cwpBbGwgb2YgdGhlIHRleHRzIGluIHRoaXMgY29ycHVzIGFyZSBhY2FkZW1pYyBhcnRpY2xlcywgc28gd2UgbWlnaHQgZXhwZWN0IHRoZW0gdG8gYmUgcmVhc29uYWJseSBzaW1pbGFyIGluIHRlcm1zIG9mIGxlbmd0aC4gV2hlbiBwbG90dGluZyB0aGUgbGVuZ3Rocywgd2UgZmluZCB0aGF0IG1vc3QgdGVuZCB0byBjZW50ZXIgYXJvdW5kIDEwLDAwMCB3b3JkcywgYnV0IHRoZXJlIGFyZSBzb21lIHZlcnkgbG9uZyBvdXRsaWVycy4KCmBgYHtyIHRva2VuIHRvdGFscywgbWVzc2FnZSA9RkFMU0V9CnRva2VuY291bnQgPC0gbnRva2VuKHJhd3Rva2Vuc19kZm0pCiNDYWxjdWxhdGUgYmlud2lkdGggd2l0aCB0aGUgRnJlZWRtYW7igJNEaWFjb25pcyBydWxlCmJpbndpZHRoX3Rva2VucyA8LSAyICogSVFSKHRva2VuY291bnQpIC8gbGVuZ3RoKHRva2VuY291bnQpXigxIC8gMykKCiNjcmVhdGUgYSBkYXRhZnJhbWUgd2l0aCB0b2tlbiBjb3VudHMgYW5kIGRpc2NpcGxpbmVzCmZ4bndvcmRfbm9ybWFsaXplZF9kZiA8LSBjb252ZXJ0KGZ4bndvcmRfbm9ybWFsaXplZF9kZm0sIHRvID0gImRhdGEuZnJhbWUiKQpmeG53b3JkX25vcm1hbGl6ZWRfZGYkd29yZGNvdW50IDwtIHRva2VuY291bnQKZnhud29yZF9ub3JtYWxpemVkX2RmJGRpc2NpcGxpbmUgPC0gbWV0YWRhdGEkRGlzY2lwbGluZQojcGxvdCBoaXN0b2dyYW0gb2YgbGVuZ3RocwpnZ3Bsb3QoZnhud29yZF9ub3JtYWxpemVkX2RmLCBhZXMoeCA9IHdvcmRjb3VudCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSBiaW53aWR0aF90b2tlbnMpICt5bGFiKCJOdW1iZXIgb2YgcGFwZXJzIikgKyB4bGFiKCJXb3JkIGNvdW50IikKYGBgCkZ1cnRoZXIgaW52ZXN0aWdhdGlvbiB0aGUgdmVyeSBsb25nIG91dGxpZXJzIGFwcGVhciB0byBiZSBkcml2ZW4gYnkgdGhlIGRpc2NpcGxpbmUgb2YgcGh5c2ljcy4KYGBge3IgbGVuZ3RoIGJ5IGRpc2NpcGxpbmUsIGVjaG89RkFMU0V9CiNwbG90IGJveHBsb3Qgb2YgbGVuZ3RocyBieSBkaXNjaXBsaW5lCmdncGxvdChkYXRhPWZ4bndvcmRfbm9ybWFsaXplZF9kZixtYXBwaW5nPWFlcyh4PXJlb3JkZXIoZGlzY2lwbGluZSwtd29yZGNvdW50LCBGVU4gPSBtZWRpYW4pLCB5PXdvcmRjb3VudCkpICsgZ2VvbV9ib3hwbG90KGNvbG9yPSJibHVlIixmaWxsPSJ3aGl0ZSIpICsgdGhlbWVfYncoKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkgKyB4bGFiKCJEaXNjaXBsaW5lIikgK3lsYWIoIldvcmQgY291bnQiKQpgYGAKCiMjIEZyZXF1ZW5jaWVzIG9mIGtleSBmdW5jdGlvbiB3b3JkcwpQcmVsaW1pbmFyeSBkYXRhIGFuYWx5c2lzIHNob3dlZCB0aGF0IHRoZSBmb2xsb3dpbmcgZnVuY3Rpb24gd29yZHMgaGFkIGxhcmdlIGRpZmZlcmVuY2VzIGluIHotc2NvcmVzIGJldHdlZW4gZGlzY2lwbGluZXM6IHdlcmUsIGhvdywgdGhleSwgYXMuIEJlbG93IGFyZSB0aGUgbm9ybWFsaXplZCBmcmVxdWVuY2llcyBvZiB0aGVzZSBmb3VyIHdvcmRzIGFjcm9zcyBkaXNjaXBsaW5lcywgc2hvd2luZyBkaWZmZXJlbmNlcy4KYGBge3IgZnJlcXVlbmN5IGNvbXBhcmlzb25zLCBtZXNzYWdlPUZBTFNFfQojcGxvdCB0aGUgZm91ciB3b3Jkcwp3ZXJlX3Bsb3QgPC0gZ2dwbG90KGRhdGE9Znhud29yZF9ub3JtYWxpemVkX2RmLG1hcHBpbmc9YWVzKHg9cmVvcmRlcihkaXNjaXBsaW5lLC13ZXJlLCBGVU4gPSBtZWRpYW4pLCB5PXdlcmUpKSArIGdlb21fYm94cGxvdChjb2xvcj0iYmx1ZSIsZmlsbD0id2hpdGUiKSArIHRoZW1lX2J3KCkgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSkpICsgeGxhYigiRGlzY2lwbGluZSIpICsgeWxhYigid2VyZSIpCgpob3dfcGxvdCA8LSBnZ3Bsb3QoZGF0YT1meG53b3JkX25vcm1hbGl6ZWRfZGYsbWFwcGluZz1hZXMoeD1yZW9yZGVyKGRpc2NpcGxpbmUsLWhvdywgRlVOID0gbWVkaWFuKSwgeT1ob3cpKSArIGdlb21fYm94cGxvdChjb2xvcj0iYmx1ZSIsZmlsbD0id2hpdGUiKSsgdGhlbWVfYncoKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkgKyB4bGFiKCJEaXNjaXBsaW5lIikgKyB5bGFiKCJob3ciKQoKdGhleV9wbG90IDwtIGdncGxvdChkYXRhPWZ4bndvcmRfbm9ybWFsaXplZF9kZixtYXBwaW5nPWFlcyh4PXJlb3JkZXIoZGlzY2lwbGluZSwtdGhleSwgRlVOID0gbWVkaWFuKSwgeT10aGV5KSkgKyBnZW9tX2JveHBsb3QoY29sb3I9ImJsdWUiLGZpbGw9IndoaXRlIikrIHRoZW1lX2J3KCkgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSkpICsgeGxhYigiRGlzY2lwbGluZSIpICsgeWxhYigidGhleSIpCgphc19wbG90IDwtIGdncGxvdChkYXRhPWZ4bndvcmRfbm9ybWFsaXplZF9kZixtYXBwaW5nPWFlcyh4PXJlb3JkZXIoZGlzY2lwbGluZSwtYXMsIEZVTiA9IG1lZGlhbiksIHk9YXMpKSArIGdlb21fYm94cGxvdChjb2xvcj0iYmx1ZSIsZmlsbD0id2hpdGUiKSsgdGhlbWVfYncoKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkgKyB4bGFiKCJEaXNjaXBsaW5lIikgKyB5bGFiKCJhcyIpCgojYXJyYW5nZSBpbnRvIGEgdmlzdWFsCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKHdlcmVfcGxvdCwgaG93X3Bsb3QsIHRoZXlfcGxvdCwgYXNfcGxvdCkKYGBgCgojIyBLZXluZXNzIGFuZCBlZmZlY3Qgc2l6ZQpUaGUgdGFibGVzIGJlbG93IGlkZW50aWZ5IDUgd29yZHMgZm9yIGVhY2ggZGlzY2lwbGluZSB0aGF0IGFyZSBrZXkgaW4gdGhhdCBkaXNjaXBsaW5lIChjb21wYXJlZCB0byBhbGwgb2YgdGhlIG90aGVyIGRpc2NpcGxpbmVzIGNvbWJpbmVkKSwgYW5kIHRoZSBlZmZlY3Qgc2l6ZSBvZiB0aG9zZSB3b3Jkcy4gVGhlc2UgdGFibGVzIGFyZSBzb3J0ZWQgYnkga2V5bmVzcyB2YWx1ZXMuIEEgaGlnaCBrZXluZXNzIHZhbHVlIGluZGljYXRlcyB0aGF0IHRoZXJlIGlzIGEgbG90IG9mIGV2aWRlbmNlIGZvciBkaWZmZXJlbmNlIGluIGZyZXF1ZW5jaWVzIG9mIHRoYXQgd29yZCBiZXR3ZWVuIGRpc2NpcGxpbmVzLCB3aGlsZSBhIGhpZ2ggZWZmZWN0IHNpemUgaW5kaWNhdGVzIHRoYXQgdGhlIGRpZmZlcmVuY2UgaXMgcXVpdGUgbGFyZ2UuIEhlcmUsIHRoZSBrZXluZXNzIGlzIGNhbGN1bGF0ZWQgdXNpbmcgbG9nLWxpa2VsaWhvb2QgYW5kIHRoZSBlZmZlY3Qgc2l6ZSBjYWxjdWxhdGVkIHVzaW5nIEhhcmRpZSdzIGxvZyByYXRpby4KYGBge3Iga2V5bmVzcyBlZmZlY3QsIG1lc3NhZ2U9RkFMU0V9CiNjcmVhdGUgZGZtIGdyb3VwZWQgYnkgZGlzY2lwbGluZQprZXluZXNzX2RmbSA8LSBkZm1fZ3JvdXAocmF3dG9rZW5zX2RmbSwgZ3JvdXBzPSJEaXNjX3Nob3J0IikKZGlzY2lwbGluZV92ZWN0b3IgPC0gdW5pcXVlKG1ldGFkYXRhJERpc2Nfc2hvcnQpCiNkZWZpbmUgZnVuY3Rpb24gZm9yIGNhbGN1bGF0aW5nIGVmZmVjdCBzaXplIHVzaW5nIEhhcmRpZSdzIGxvZyByYXRpbwplZmZlY3Rfc2l6ZSA8LSBmdW5jdGlvbiAobl90YXJnZXQsIG5fcmVmZXJlbmNlKSB7CiAgdG90YWxfYSA8LSBzdW0obl90YXJnZXQpCiAgdG90YWxfYiA8LSBzdW0obl9yZWZlcmVuY2UpCiAgcGVyY2VudF9hIDwtIGlmZWxzZShuX3RhcmdldCA9PSAwLCAwLjUgLyB0b3RhbF9hLCBuX3RhcmdldC90b3RhbF9hKQogIHBlcmNlbnRfYiA8LSBpZmVsc2Uobl9yZWZlcmVuY2UgPT0gMCwgMC41IC8gdG90YWxfYiwgbl9yZWZlcmVuY2UvdG90YWxfYikKICByYXRpbyA8LSBsb2cyKHBlcmNlbnRfYSAvIHBlcmNlbnRfYikKICByZXR1cm4ocmF0aW8pCn0KI2NyZWF0ZSBsaXN0IHRvIHN0b3JlIHZhbHVlcyBpbiBhbmQgZGF0YSBmcmFtZSB0byBwcmludAprZXl3b3JkcyA8LSBsaXN0KCkKa2V5d29yZF90YWJsZSA8LSBkYXRhLmZyYW1lKCkKI2xvb3AgdGhyb3VnaCBkaXNjaXBsaW5lcyBhbmQgc3RvcmUgdmFsdWVzIGluIGtleXdvcmRzIGxpc3QKI3lvdSBjYW4gbm93IGFjY2VzcyBhbnkgZGlzY2lwbGluZSdzIGtleW5lc3MgYW5kIGVmZmVjdCBzaXplIHZhbHVlcyB3aXRoIGtleXdvcmRzW1snW2Rpc2NdJ11dLiBFeDoga2V5d29yZHNbWydjcyddXQpmb3IgKGkgaW4gMTpsZW5ndGgoZGlzY2lwbGluZV92ZWN0b3IpKSB7CiAgI2dldCBrZXl3b3JkcwogIGtleXdvcmRzW1tkaXNjaXBsaW5lX3ZlY3RvcltpXV1dIDwtIHRleHRzdGF0X2tleW5lc3Moa2V5bmVzc19kZm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldD1kaXNjaXBsaW5lX3ZlY3RvcltpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZSA9ICJsciIpCiAgI2FkZCBlZmZlY3Qgc2l6ZQogIGtleXdvcmRzW1tkaXNjaXBsaW5lX3ZlY3RvcltpXV1dIDwtIGtleXdvcmRzW1tkaXNjaXBsaW5lX3ZlY3RvcltpXV1dICU+JSAKICAgIG11dGF0ZSguLCBlZmZlY3QgPSBlZmZlY3Rfc2l6ZShuX3RhcmdldCwgbl9yZWZlcmVuY2UpKQogICN0YWtlIGF3YXkgdGFyZ2V0IGFuZCByZWZlcmVuY2UgY291bnRzCiAgcHIgPC0gZHBseXI6OnNlbGVjdChhcy5kYXRhLmZyYW1lKGtleXdvcmRzW1tkaXNjaXBsaW5lX3ZlY3RvcltpXV1dKSwgLW5fdGFyZ2V0LCAtbl9yZWZlcmVuY2UpCiAgI3JlbmFtZSBjb2x1bW5zCiAgbmFtZXMocHIpWzJdIDwtICdrZXluZXNzJwogIG5hbWVzKHByKVszXSA8LSAncC12YWx1ZScKICBuYW1lcyhwcilbNF0gPC0gJ2VmZmVjdCBzaXplJwogICNhcHBlbmQgdG8gdGFibGUgZm9yIHByaW50aW5nICYgc2F2ZSBkaXNjaXBsaW5lIG5hbWUKICBrZXl3b3JkX3RhYmxlIDwtIHJiaW5kKGtleXdvcmRfdGFibGUsIGZvcm1hdChoZWFkKHByLG49NSksIG5zbWFsbD0zLCBkaWdpdHM9MykpCn0KI3ByaW50IHRhYmxlcwpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmthYmxlKGtleXdvcmRfdGFibGUsIGNhcHRpb24gPSAiS2V5bmVzcyBhbmQgRWZmZWN0IFNpemUiKSAlPiUKICBrYWJsZV9zdHlsaW5nKCJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IEYpICU+JQogIHBhY2tfcm93cyhkaXNjaXBsaW5lX3ZlY3RvcltbMV1dLCAxLDUpICU+JQogIHBhY2tfcm93cyhkaXNjaXBsaW5lX3ZlY3RvcltbMl1dLCA2LDEwKSAlPiUKICBwYWNrX3Jvd3MoZGlzY2lwbGluZV92ZWN0b3JbWzNdXSwgMTEsMTUpICU+JQogIHBhY2tfcm93cyhkaXNjaXBsaW5lX3ZlY3RvcltbNF1dLCAxNiwgMjApICU+JQogIHBhY2tfcm93cyhkaXNjaXBsaW5lX3ZlY3RvcltbNV1dLCAyMSwyNSkgJT4lCiAgcGFja19yb3dzKGRpc2NpcGxpbmVfdmVjdG9yW1s2XV0sIDI2LCAzMCkgJT4lCiAgcGFja19yb3dzKGRpc2NpcGxpbmVfdmVjdG9yW1s3XV0sIDMxLDM1KSAlPiUKICBwYWNrX3Jvd3MoZGlzY2lwbGluZV92ZWN0b3JbWzhdXSwgMzYsIDQwKSAlPiUKICBwYWNrX3Jvd3MoZGlzY2lwbGluZV92ZWN0b3JbWzldXSwgNDEsNDUpICU+JQogIHBhY2tfcm93cyhkaXNjaXBsaW5lX3ZlY3RvcltbMTBdXSwgNDYsIDUwKSAlPiUKICBwYWNrX3Jvd3MoZGlzY2lwbGluZV92ZWN0b3JbWzExXV0sIDUxLDU1KSAlPiUKICBwYWNrX3Jvd3MoZGlzY2lwbGluZV92ZWN0b3JbWzEyXV0sIDU2LCA2MCkgJT4lCiAgcGFja19yb3dzKGRpc2NpcGxpbmVfdmVjdG9yW1sxM11dLCA2MSw2NSkKYGBgCgojIFN0eWxvbWV0cnkKSW4gdGhpcyBzZWN0aW9uLCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBob3cgcGFwZXJzIGNsdXN0ZXIgdG9nZXRoZXIgYmFzZWQgb24gdGhlICJkaXN0YW5jZXMiIGJldHdlZW4gdGhlbSwgYW5kIHdoYXQgcGFydGljdWxhciB3b3JkcyBhcmUgZHJpdmluZyB0aGVzZSBjbHVzdGVycy4KClRoZXJlIGFyZSBtYW55IGRpZmZlcmVudCB3YXlzIHRvIGNhbGN1bGF0ZSB0aGUgZGlzdGFuY2VzIGJldHdlZW4gdGV4dHMuIFNvbWUgY29tbW9uIGRpc3RhbmNlIG1lYXN1cmVtZW50cyBpbmNsdWRlIEV1Y2xpZGVhbiwgRGVsdGEsIE1hbmhhdHRhbiwgQXJnYW1vbidzLCBDYW5iZXJyYSwgV3VyemJ1cmcsIENvc2luZSwgYW5kIE1pbi1NYXguIFRoZSBiYXNpYyBpZGVhIGJlaGluZCBhbGwgb2YgdGhlc2UgaXMgdG8gcmVwcmVzZW50IGhvdyBzaW1pbGFyIHR3byB0ZXh0cyBhcmUsIGJhc2VkIG9uIGhvdyBzaW1pbGFyIHRoZWlyIGRpc3RyaWJ1dGlvbnMgb2YgZnVuY3Rpb24gd29yZHMgYXJlLiBUaHVzLCB0ZXh0cyB3aXRoIHZlcnkgc2ltaWxhciBkaXN0cmlidXRpb25zIG9mIGZ1bmN0aW9uIHdvcmRzIGdldCBhIGxvd2VyIGRpc3RhbmNlLiBUaGUgbWV0aG9kcyB2YXJ5IGluIHRoZWlyIHByZWNpc2UgYWxnb3JpdGhtIHRvIGNhbGN1bGF0ZSB0aGlzIGRpc3RhbmNlLgoKRWFjaCBncmFwaCBiZWxvdyB1c2VzIGEgZGlmZmVyZW50IGRpc3RhbmNlIG1lYXN1cmVtZW50LiBCYXNlZCBvbiB0aGVzZSBkaXN0YW5jZXMsIHRoZSBkZW5kcm9ncmFtcyBiZWxvdyBhcmUgY3JlYXRlZCB1c2luZyBhZ2dsb21lcmF0aXZlIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nLiBFYWNoIG5vZGUgYXQgdGhlIHJpZ2h0IHJlcHJlc2VudHMgb25lIHRleHQsIGNvbG9yLWNvZGVkIGJ5IGRpc2NpcGxpbmUuIEl0IGlzIG5vdCBpbXBvcnRhbnQgKG9yIGZlYXNpYmxlKSBoZXJlIHRvIHNlZSBhbGwgb2YgdGhlIHRleHQgbmFtZXMsIGJ1dCBpdCBpcyBpbnRlcmVzdGluZyB0byBzZWUgd2hpY2ggZGlzdGFuY2UgYWxnb3JpdGhtIHByb2R1Y2VzIHRoZSBiZXN0IGNsdXN0ZXJpbmcgb2YgcGFwZXJzIChpbiBvdGhlciB3b3Jkcywgd2hpY2ggZ3JhcGggc2hvd3MgdGhlIGNvbG9ycyBtb3N0IHRpZ2h0bHkgZ3JvdXBlZCB0b2dldGhlcikuIEl0IGFwcGVhcnMgdGhhdCBNYW5oYXR0YW4gYW5kIERlbHRhIGFyZSBkb2luZyBhIGZhaXJseSBnb29kIGpvYiwgd2hpbGUgRXVjbGlkZWFuIGFuZCBXdXJ6YnVyZyBzZWVtIGEgbGl0dGxlIG1lc3NpZXIuCmBgYCB7ciBkaXN0YW5jZXMsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQojY3JlYXRlIGRhdGEgZnJhbWUgZm9yIGFuYWx5c2lzCnN0eWxvX2RmPC1kcGx5cjo6c2VsZWN0KGZ4bndvcmRfbm9ybWFsaXplZF9kZiwgLXdvcmRjb3VudCwgLWRpc2NpcGxpbmUpICU+JSBkYXRhLmZyYW1lKC4sIHJvdy5uYW1lcz0xKQoKI3J1biByZXN1bHRzIHcgdmFyaW91cyBkaXN0YW5jZSBtZWFzdXJlcwpzdHlsb19ldWNsaWRlYW5fcmVzdWx0cyA8LSBzdHlsbzo6c3R5bG8oZ3VpPUZBTFNFLCBmcmVxdWVuY2llcyA9IHN0eWxvX2RmLCBtZncubWluID0gMjQwLCBtZncubWF4PTI0MCwgcGxvdC5jdXN0b20uaGVpZ2h0ID0gMTMsIHBsb3QuZm9udC5zaXplID0gMS44LCBkaXN0YW5jZS5tZWFzdXJlPSdldWNsaWRlYW4nLCBkaXNwbGF5Lm9uLnNjcmVlbiA9IEZBTFNFLCB3cml0ZS5qcGcuZmlsZSA9IFRSVUUpCgpzdHlsb19kZWx0YV9yZXN1bHRzIDwtIHN0eWxvOjpzdHlsbyhndWk9RkFMU0UsIGZyZXF1ZW5jaWVzID0gc3R5bG9fZGYsIG1mdy5taW4gPSAyNDAsIG1mdy5tYXg9MjQwLCBwbG90LmN1c3RvbS5oZWlnaHQgPSAxMywgcGxvdC5mb250LnNpemUgPSAxLjgsIGRpc3RhbmNlLm1lYXN1cmU9J2RlbHRhJywgZGlzcGxheS5vbi5zY3JlZW4gPSBGQUxTRSwgd3JpdGUuanBnLmZpbGUgPSBUUlVFLCB3cml0ZS5qcGcuZmlsZSA9IFRSVUUpCgpzdHlsb19tYW5oYXR0YW5fcmVzdWx0cyA8LSBzdHlsbzo6c3R5bG8oZ3VpPUZBTFNFLCBmcmVxdWVuY2llcyA9IHN0eWxvX2RmLCBtZncubWluID0gMjQwLCBtZncubWF4PTI0MCwgcGxvdC5jdXN0b20uaGVpZ2h0ID0gMTMsIHBsb3QuZm9udC5zaXplID0gMS44LCBkaXN0YW5jZS5tZWFzdXJlPSdtYW5oYXR0YW4nLCBkaXNwbGF5Lm9uLnNjcmVlbiA9IEZBTFNFLCB3cml0ZS5qcGcuZmlsZSA9IFRSVUUpCgpzdHlsb19hcmdhbW9uX3Jlc3VsdHMgPC0gc3R5bG86OnN0eWxvKGd1aT1GQUxTRSwgZnJlcXVlbmNpZXMgPSBzdHlsb19kZiwgbWZ3Lm1pbiA9IDI0MCwgbWZ3Lm1heD0yNDAsIHBsb3QuY3VzdG9tLmhlaWdodCA9IDEzLCBwbG90LmZvbnQuc2l6ZSA9IDEuOCwgZGlzdGFuY2UubWVhc3VyZT0nYXJnYW1vbicsIGRpc3BsYXkub24uc2NyZWVuID0gRkFMU0UsIHdyaXRlLmpwZy5maWxlID0gVFJVRSkKCnN0eWxvX2NhbmJlcnJhX3Jlc3VsdHMgPC0gc3R5bG86OnN0eWxvKGd1aT1GQUxTRSwgZnJlcXVlbmNpZXMgPSBzdHlsb19kZiwgbWZ3Lm1pbiA9IDI0MCwgbWZ3Lm1heD0yNDAsIHBsb3QuY3VzdG9tLmhlaWdodCA9IDEzLCBwbG90LmZvbnQuc2l6ZSA9IDEuOCwgZGlzdGFuY2UubWVhc3VyZT0nY2FuYmVycmEnLCBkaXNwbGF5Lm9uLnNjcmVlbiA9IEZBTFNFLCB3cml0ZS5qcGcuZmlsZSA9IFRSVUUpCgpzdHlsb193dXJ6YnVyZ19yZXN1bHRzIDwtIHN0eWxvOjpzdHlsbyhndWk9RkFMU0UsIGZyZXF1ZW5jaWVzID0gc3R5bG9fZGYsIG1mdy5taW4gPSAyNDAsIG1mdy5tYXg9MjQwLCBwbG90LmN1c3RvbS5oZWlnaHQgPSAxMywgcGxvdC5mb250LnNpemUgPSAxLjgsIGRpc3RhbmNlLm1lYXN1cmU9J3d1cnpidXJnJywgZGlzcGxheS5vbi5zY3JlZW4gPSBGQUxTRSwgd3JpdGUuanBnLmZpbGUgPSBUUlVFKQoKc3R5bG9fY29zaW5lX3Jlc3VsdHMgPC0gc3R5bG86OnN0eWxvKGd1aT1GQUxTRSwgZnJlcXVlbmNpZXMgPSBzdHlsb19kZiwgbWZ3Lm1pbiA9IDI0MCwgbWZ3Lm1heD0yNDAsIHBsb3QuY3VzdG9tLmhlaWdodCA9IDEzLCBwbG90LmZvbnQuc2l6ZSA9IDEuOCwgZGlzdGFuY2UubWVhc3VyZT0nY29zaW5lJywgZGlzcGxheS5vbi5zY3JlZW4gPSBGQUxTRSwgd3JpdGUuanBnLmZpbGUgPSBUUlVFKQoKc3R5bG9fbWlubWF4X3Jlc3VsdHMgPC0gc3R5bG86OnN0eWxvKGd1aT1GQUxTRSwgZnJlcXVlbmNpZXMgPSBzdHlsb19kZiwgbWZ3Lm1pbiA9IDI0MCwgbWZ3Lm1heD0yNDAsIHBsb3QuY3VzdG9tLmhlaWdodCA9IDEzLCBwbG90LmZvbnQuc2l6ZSA9IDEuOCwgZGlzdGFuY2UubWVhc3VyZT0nbWlubWF4JywgZGlzcGxheS5vbi5zY3JlZW4gPSBGQUxTRSwgd3JpdGUuanBnLmZpbGUgPSBUUlVFKQpgYGAKCmBgYCB7ciBwbG90IGdyaWQgb2YgZGVuZHJvZ3JhbXMsIGVjaG89RkFMU0V9CiNyZWFkIGluIGpwZyBmaWxlcwpsaWJyYXJ5KGdyaWQpCmFyZ2Ftb25wbG90PC1yYXN0ZXJHcm9iKGpwZWc6OnJlYWRKUEVHKCJkaXNzZXJ0YXRpb25fQ0FfMjM4X01GV3NfQ3VsbGVkXzBfX0FyZ2Ftb24ncyBEZWx0YV9fMDAxLmpwZyIpKQpjYW5iZXJyYXBsb3Q8LXJhc3Rlckdyb2IoanBlZzo6cmVhZEpQRUcoImRpc3NlcnRhdGlvbl9DQV8yMzhfTUZXc19DdWxsZWRfMF9fQ2FuYmVycmFfXzAwMS5qcGciKSkKZGVsdGFwbG90PC1yYXN0ZXJHcm9iKGpwZWc6OnJlYWRKUEVHKCJkaXNzZXJ0YXRpb25fQ0FfMjM4X01GV3NfQ3VsbGVkXzBfX0NsYXNzaWMgRGVsdGFfXzAwMS5qcGciKSkKY29zaW5lcGxvdDwtcmFzdGVyR3JvYihqcGVnOjpyZWFkSlBFRygiZGlzc2VydGF0aW9uX0NBXzIzOF9NRldzX0N1bGxlZF8wX19Db3NpbmVfXzAwMS5qcGciKSkKZXVjbGlkZWFucGxvdDwtcmFzdGVyR3JvYihqcGVnOjpyZWFkSlBFRygiZGlzc2VydGF0aW9uX0NBXzIzOF9NRldzX0N1bGxlZF8wX19FdWNsaWRlYW5fXzAwMS5qcGciKSkKbWFuaGF0dGFucGxvdDwtcmFzdGVyR3JvYihqcGVnOjpyZWFkSlBFRygiZGlzc2VydGF0aW9uX0NBXzIzOF9NRldzX0N1bGxlZF8wX19NYW5oYXR0YW5fXzAwMS5qcGciKSkKbWlubWF4cGxvdDwtcmFzdGVyR3JvYihqcGVnOjpyZWFkSlBFRygiZGlzc2VydGF0aW9uX0NBXzIzOF9NRldzX0N1bGxlZF8wX19taW5tYXhfXzAwMS5qcGciKSkKd3VyemJ1cmdwbG90PC1yYXN0ZXJHcm9iKGpwZWc6OnJlYWRKUEVHKCJkaXNzZXJ0YXRpb25fQ0FfMjM4X01GV3NfQ3VsbGVkXzBfX3d1cnpidXJnX18wMDEuanBnIikpCgojYXJyYW5nZSBwbG90cyBhbmQgcHJpbnQKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoZ3JpZEV4dHJhOjphcnJhbmdlR3JvYihhcmdhbW9ucGxvdCwgYm90dG9tID0gIkFyZ2Ftb24iKSwgZ3JpZEV4dHJhOjphcnJhbmdlR3JvYihjYW5iZXJyYXBsb3QsIGJvdHRvbSA9ICJDYW5iZXJyYSIpLCBuY29sID0gMikKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoZ3JpZEV4dHJhOjphcnJhbmdlR3JvYihkZWx0YXBsb3QsIGJvdHRvbSA9ICJEZWx0YSIpLCBncmlkRXh0cmE6OmFycmFuZ2VHcm9iKGNvc2luZXBsb3QsIGJvdHRvbSA9ICJDb3NpbmUiKSwgbmNvbCA9IDIpCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGdyaWRFeHRyYTo6YXJyYW5nZUdyb2IoZXVjbGlkZWFucGxvdCwgYm90dG9tID0gIkV1Y2xpZGVhbiIpLCBncmlkRXh0cmE6OmFycmFuZ2VHcm9iKG1hbmhhdHRhbnBsb3QsYm90dG9tID0gIk1hbmhhdHRhbiIpLG5jb2wgPSAyKQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShncmlkRXh0cmE6OmFycmFuZ2VHcm9iKG1pbm1heHBsb3QsIGJvdHRvbSA9ICJNaW4tTWF4IiksIGdyaWRFeHRyYTo6YXJyYW5nZUdyb2Iod3VyemJ1cmdwbG90LCBib3R0b20gPSAiV3VyemJ1cmciKSxuY29sID0gMikKYGBgCgpJbiB0aGUga2V5bmVzcyBhbmQgZWZmZWN0IHNpemUgdGFibGVzLCBpdCBiZWNhbWUgYXBwYXJlbnQgdGhhdCBwcm9ub3VucyB3ZXJlIHBsYXlpbmcgYSBsYXJnZSByb2xlIGluIGRpc2NpcGxpbmFyeSBkaXNjb3Vyc2UuIEJlY2F1c2UgcHJvbm91biB1c2UgbWlnaHQgYmUgaW50dWl0aXZlIGluIHNvbWUgY2FzZXMgKGZvciBleGFtcGxlLCBoaXN0b3J5IG1heSB1c2UgYSBsb3Qgb2YgImhlIiB0byB0YWxrIGFib3V0IGhpc3RvcmljYWwgbWFsZSBmaWd1cmVzIHRoYXQgaGF2ZSBiZWVuIGhpc3RvcmljYWxseSBvdmVycnJlcHJlc2VudGVkIGluIGNvbXBhcmlzb24gdG8gd29tZW4pLCBpdCBtYXkgYmUgaW50ZXJlc3RpbmcgdG8gZXhwbG9yZSBkaXNjaXBsaW5hcnkgZGlmZmVyZW5jZXMgd2hlbiBwcm9ub3VucyBhcmUgbm90IGluY2x1ZGVkIGluIHRoZSBmdW5jdGlvbiB3b3JkcyBhbmFseXplZC4gVGhlIGdyYXBocyBiZWxvdyByZXBlYXQgdGhlIGFuYWx5c2lzIGRvbmUgYmVmb3JlLCBidXQgd2l0aCBwcm9ub3VucyBsZWZ0IG91dC4KCmBgYCB7ciBkaXN0YW5jZXMgbm8gcHJvbm91bnMsIGVjaG89RkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KI2NyZWF0ZSBkYXRhIGZyYW1lIGZvciBhbmFseXNpcwpzdHlsb19kZl9ub3Byb25vdW5zPC1kcGx5cjo6c2VsZWN0KGZ4bndvcmRfbm9ybWFsaXplZF9kZiwgLXdvcmRjb3VudCwgLWRpc2NpcGxpbmUsIC1oZXJzZWxmLCAtdGhlaXJzLCAtb3Vyc2VsdmVzLCAtbWluZSwgLXlvdSwgLWhpbSwgLXRoZWlyLCAtdXMsIC13ZSwgLXRoZXksIC10aGVtLCAtb3VycywgLWksIC1oaXMsIC1oZXIsIC1oZSwgLXNoZSwgLXRoZW1zZWx2ZXMsIC15b3VyLCAtbXksIC1oaW1zZWxmLCAtbWUsIC1teXNlbGYsIC15b3Vyc2VsZiwgLWhlcnMsIC1vbmVzZWxmLCAteW91cnMsIC15b3Vyc2VsdmVzLCAtdGhlbXNlbGYpICU+JSBkYXRhLmZyYW1lKC4sIHJvdy5uYW1lcz0xKQoKI3J1biByZXN1bHRzIHcgdmFyaW91cyBkaXN0YW5jZSBtZWFzdXJlcwpzdHlsb19ldWNsaWRlYW5fcmVzdWx0c19ub3Byb25vdW5zIDwtIHN0eWxvOjpzdHlsbyhndWk9RkFMU0UsIGZyZXF1ZW5jaWVzID0gc3R5bG9fZGZfbm9wcm9ub3VucywgbWZ3Lm1pbiA9IDI0MCwgbWZ3Lm1heD0yNDAsIHBsb3QuY3VzdG9tLmhlaWdodCA9IDEzLCBwbG90LmZvbnQuc2l6ZSA9IDEuOCwgZGlzdGFuY2UubWVhc3VyZT0nZXVjbGlkZWFuJywgZGlzcGxheS5vbi5zY3JlZW4gPSBGQUxTRSwgd3JpdGUucG5nLmZpbGUgPSBUUlVFKQoKc3R5bG9fZGVsdGFfcmVzdWx0c19ub3Byb25vdW5zIDwtIHN0eWxvOjpzdHlsbyhndWk9RkFMU0UsIGZyZXF1ZW5jaWVzID0gc3R5bG9fZGZfbm9wcm9ub3VucywgbWZ3Lm1pbiA9IDI0MCwgbWZ3Lm1heD0yNDAsIHBsb3QuY3VzdG9tLmhlaWdodCA9IDEzLCBwbG90LmZvbnQuc2l6ZSA9IDEuOCwgZGlzdGFuY2UubWVhc3VyZT0nZGVsdGEnLCBkaXNwbGF5Lm9uLnNjcmVlbiA9IEZBTFNFLCB3cml0ZS5wbmcuZmlsZSA9IFRSVUUpCgpzdHlsb19tYW5oYXR0YW5fcmVzdWx0c19ub3Byb25vdW5zIDwtIHN0eWxvOjpzdHlsbyhndWk9RkFMU0UsIGZyZXF1ZW5jaWVzID0gc3R5bG9fZGZfbm9wcm9ub3VucywgbWZ3Lm1pbiA9IDI0MCwgbWZ3Lm1heD0yNDAsIHBsb3QuY3VzdG9tLmhlaWdodCA9IDEzLCBwbG90LmZvbnQuc2l6ZSA9IDEuOCwgZGlzdGFuY2UubWVhc3VyZT0nbWFuaGF0dGFuJywgZGlzcGxheS5vbi5zY3JlZW4gPSBGQUxTRSwgd3JpdGUucG5nLmZpbGUgPSBUUlVFKQoKc3R5bG9fYXJnYW1vbl9yZXN1bHRzX25vcHJvbm91bnMgPC0gc3R5bG86OnN0eWxvKGd1aT1GQUxTRSwgZnJlcXVlbmNpZXMgPSBzdHlsb19kZl9ub3Byb25vdW5zLCBtZncubWluID0gMjQwLCBtZncubWF4PTI0MCwgcGxvdC5jdXN0b20uaGVpZ2h0ID0gMTMsIHBsb3QuZm9udC5zaXplID0gMS44LCBkaXN0YW5jZS5tZWFzdXJlPSdhcmdhbW9uJywgZGlzcGxheS5vbi5zY3JlZW4gPSBGQUxTRSwgd3JpdGUucG5nLmZpbGUgPSBUUlVFKQoKc3R5bG9fY2FuYmVycmFfcmVzdWx0c19ub3Byb25vdW5zIDwtIHN0eWxvOjpzdHlsbyhndWk9RkFMU0UsIGZyZXF1ZW5jaWVzID0gc3R5bG9fZGZfbm9wcm9ub3VucywgbWZ3Lm1pbiA9IDI0MCwgbWZ3Lm1heD0yNDAsIHBsb3QuY3VzdG9tLmhlaWdodCA9IDEzLCBwbG90LmZvbnQuc2l6ZSA9IDEuOCwgZGlzdGFuY2UubWVhc3VyZT0nY2FuYmVycmEnLCBkaXNwbGF5Lm9uLnNjcmVlbiA9IEZBTFNFLCB3cml0ZS5wbmcuZmlsZSA9IFRSVUUpCgpzdHlsb193dXJ6YnVyZ19yZXN1bHRzX25vcHJvbm91bnMgPC0gc3R5bG86OnN0eWxvKGd1aT1GQUxTRSwgZnJlcXVlbmNpZXMgPSBzdHlsb19kZl9ub3Byb25vdW5zLCBtZncubWluID0gMjQwLCBtZncubWF4PTI0MCwgcGxvdC5jdXN0b20uaGVpZ2h0ID0gMTMsIHBsb3QuZm9udC5zaXplID0gMS44LCBkaXN0YW5jZS5tZWFzdXJlPSd3dXJ6YnVyZycsIGRpc3BsYXkub24uc2NyZWVuID0gRkFMU0UsIHdyaXRlLnBuZy5maWxlID0gVFJVRSkKCnN0eWxvX2Nvc2luZV9yZXN1bHRzX25vcHJvbm91bnMgPC0gc3R5bG86OnN0eWxvKGd1aT1GQUxTRSwgZnJlcXVlbmNpZXMgPSBzdHlsb19kZl9ub3Byb25vdW5zLCBtZncubWluID0gMjQwLCBtZncubWF4PTI0MCwgcGxvdC5jdXN0b20uaGVpZ2h0ID0gMTMsIHBsb3QuZm9udC5zaXplID0gMS44LCBkaXN0YW5jZS5tZWFzdXJlPSdjb3NpbmUnLCBkaXNwbGF5Lm9uLnNjcmVlbiA9IEZBTFNFLCB3cml0ZS5wbmcuZmlsZSA9IFRSVUUpCgpzdHlsb19taW5tYXhfcmVzdWx0c19ub3Byb25vdW5zIDwtIHN0eWxvOjpzdHlsbyhndWk9RkFMU0UsIGZyZXF1ZW5jaWVzID0gc3R5bG9fZGZfbm9wcm9ub3VucywgbWZ3Lm1pbiA9IDI0MCwgbWZ3Lm1heD0yNDAsIHBsb3QuY3VzdG9tLmhlaWdodCA9IDEzLCBwbG90LmZvbnQuc2l6ZSA9IDEuOCwgZGlzdGFuY2UubWVhc3VyZT0nbWlubWF4JywgZGlzcGxheS5vbi5zY3JlZW4gPSBGQUxTRSwgd3JpdGUucG5nLmZpbGUgPSBUUlVFKQpgYGAKCmBgYCB7ciBwbG90IGdyaWQgb2YgZGVuZHJvZ3JhbXMgbm8gcHJvbm91bnMsIGVjaG89RkFMU0V9CiNyZWFkIGluIGltYWdlIGZpbGVzCmxpYnJhcnkoZ3JpZCkKYXJnYW1vbnBsb3Rfbm9wcm9ub3VuczwtcmFzdGVyR3JvYihwbmc6OnJlYWRQTkcoImRpc3NlcnRhdGlvbl9DQV8yMDlfTUZXc19DdWxsZWRfMF9fQXJnYW1vbidzIERlbHRhX18wMDEucG5nIikpCmNhbmJlcnJhcGxvdF9ub3Byb25vdW5zPC1yYXN0ZXJHcm9iKHBuZzo6cmVhZFBORygiZGlzc2VydGF0aW9uX0NBXzIwOV9NRldzX0N1bGxlZF8wX19DYW5iZXJyYV9fMDAxLnBuZyIpKQpkZWx0YXBsb3Rfbm9wcm9ub3VuczwtcmFzdGVyR3JvYihwbmc6OnJlYWRQTkcoImRpc3NlcnRhdGlvbl9DQV8yMDlfTUZXc19DdWxsZWRfMF9fQ2xhc3NpYyBEZWx0YV9fMDAxLnBuZyIpKQpjb3NpbmVwbG90X25vcHJvbm91bnM8LXJhc3Rlckdyb2IocG5nOjpyZWFkUE5HKCJkaXNzZXJ0YXRpb25fQ0FfMjA5X01GV3NfQ3VsbGVkXzBfX0Nvc2luZV9fMDAxLnBuZyIpKQpldWNsaWRlYW5wbG90X25vcHJvbm91bnM8LXJhc3Rlckdyb2IocG5nOjpyZWFkUE5HKCJkaXNzZXJ0YXRpb25fQ0FfMjA5X01GV3NfQ3VsbGVkXzBfX0V1Y2xpZGVhbl9fMDAxLnBuZyIpKQptYW5oYXR0YW5wbG90X25vcHJvbm91bnM8LXJhc3Rlckdyb2IocG5nOjpyZWFkUE5HKCJkaXNzZXJ0YXRpb25fQ0FfMjA5X01GV3NfQ3VsbGVkXzBfX01hbmhhdHRhbl9fMDAxLnBuZyIpKQptaW5tYXhwbG90X25vcHJvbm91bnM8LXJhc3Rlckdyb2IocG5nOjpyZWFkUE5HKCJkaXNzZXJ0YXRpb25fQ0FfMjA5X01GV3NfQ3VsbGVkXzBfX21pbm1heF9fMDAxLnBuZyIpKQp3dXJ6YnVyZ3Bsb3Rfbm9wcm9ub3VuczwtcmFzdGVyR3JvYihwbmc6OnJlYWRQTkcoImRpc3NlcnRhdGlvbl9DQV8yMDlfTUZXc19DdWxsZWRfMF9fd3VyemJ1cmdfXzAwMS5wbmciKSkKCiNhcnJhbmdlIGFuZCBwcmludCBpbWFnZSBmaWxlcwpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShncmlkRXh0cmE6OmFycmFuZ2VHcm9iKGFyZ2Ftb25wbG90X25vcHJvbm91bnMsYm90dG9tID0gIkFyZ2Ftb24sIG5vIHByb25vdW5zIiksIGdyaWRFeHRyYTo6YXJyYW5nZUdyb2IoY2FuYmVycmFwbG90X25vcHJvbm91bnMsYm90dG9tID0gIkNhbmJlcnJhLCBubyBwcm9ub3VucyIpLCBuY29sID0gMikKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoZ3JpZEV4dHJhOjphcnJhbmdlR3JvYihkZWx0YXBsb3Rfbm9wcm9ub3Vucyxib3R0b20gPSAiRGVsdGEsIG5vIHByb25vdW5zIiksIGdyaWRFeHRyYTo6YXJyYW5nZUdyb2IoY29zaW5lcGxvdF9ub3Byb25vdW5zLGJvdHRvbSA9ICJDb3NpbmUsIG5vIHByb25vdW5zIiksbmNvbCA9IDIpCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGdyaWRFeHRyYTo6YXJyYW5nZUdyb2IoZXVjbGlkZWFucGxvdF9ub3Byb25vdW5zLGJvdHRvbSA9ICJFdWNsaWRlYW4sIG5vIHByb25vdW5zIiksIGdyaWRFeHRyYTo6YXJyYW5nZUdyb2IobWFuaGF0dGFucGxvdF9ub3Byb25vdW5zLGJvdHRvbSA9ICJNYW5oYXR0YW4sIG5vIHByb25vdW5zIiksIG5jb2wgPSAyKQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShncmlkRXh0cmE6OmFycmFuZ2VHcm9iKG1pbm1heHBsb3Rfbm9wcm9ub3Vucyxib3R0b20gPSAiTWluLU1heCwgbm8gcHJvbm91bnMiKSwgZ3JpZEV4dHJhOjphcnJhbmdlR3JvYih3dXJ6YnVyZ3Bsb3Rfbm9wcm9ub3VucywgYm90dG9tID0gIld1cnpidXJnLCBubyBwcm9ub3VucyIpLG5jb2wgPSAyKQpgYGAKCkRlbHRhIGFwcGVhcnMgdG8gYmUgb25lIG9mIHRoZSBzdHJvbmdlc3Qgb3V0IG9mIGVhY2ggbWVhc3VyZW1lbnQgdGVzdGVkLCBhbmQgYWxzbyBoYXMgYSBsb3Qgb2YgcHJldmlvdXMgcmVzZWFyY2ggYXJvdW5kIGl0IHRvIHN1Z2dlc3QgaXRzIHN0cmVuZ3RoIGluIGF1dGhvcnNoaXAgYXR0cmlidXRpb24gKG5vdGUgdGhhdCBNYW5oYXR0YW4gaXMgYWxzbyBlc3BlY2lhbGx5IHN0cm9uZywgYW5kIGl0IG1heSBiZSB3b3J0aCBleHBsb3Jpbmcgc29tZSBvZiB0aGUgcmVhc29ucyBmb3IgdGhpcykuIFRoZSBmaWd1cmVzIGJlbG93IHNob3cgYm90aCBjbHVzdGVyIGFuYWx5c2VzIHVzaW5nIHRoZSBEZWx0YSBtZWFzdXJlbWVudCwgYm90aCB3aXRoIGFuZCB3aXRob3V0IHByb25vdW5zLCBmb3IgY29tcGFyaXNvbi4gVGhlcmUgYXJlIG5vdCBtYWpvciBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSB0d28sIHRob3VnaCB3aXRob3V0IHByb25vdW5zIGFwcGVhcnMgdG8gYmUgc2xpZ2h0bHkgbW9yZSBhY2N1cmF0ZSBpbiBncm91cGluZyBkaXNjaXBsaW5lcy4gVGhlIGNsdXN0ZXJzIHRoZW1zZWx2ZXMgYXJlIGFsc28gc29tZXdoYXQgZGlmZmVyZW50LgpgYGB7ciBkZWx0YSBwcm9ub3VuIGNvbXBhcmlzb24sIGVjaG89RkFMU0V9CmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGdyaWRFeHRyYTo6YXJyYW5nZUdyb2IoZGVsdGFwbG90LGJvdHRvbT0iV2l0aCBwcm9ub3VucyIpLCBncmlkRXh0cmE6OmFycmFuZ2VHcm9iKGRlbHRhcGxvdF9ub3Byb25vdW5zLCBib3R0b209IldpdGhvdXQgcHJvbm91bnMiKSxuY29sID0gMikKYGBgCgpBbm90aGVyIHdheSB0byB2aXN1YWxpemUgdGhlIGRpc3RhbmNlcyBoZXJlIGlzIHRocm91Z2ggdGVjaG5pcXVlcyBkcmF3biBmcm9tIG5ldHdvcmsgYW5hbHlzaXMsIGFzIGxhaWQgb3V0IGluIEVkZXIgKDIwMTcpLiBXaGVuIGRlbmRyb2dyYW1zIGFyZSBjcmVhdGVkIGZyb20gdGhlIGJvdHRvbS11cCwgdGhlIHR3byBub2RlcyB3aXRoIHRoZSBzbWFsbGVzdCBkaXN0YW5jZSBhcmUgY29ubmVjdGVkLCB3aGljaCBkaXNyZWdhcmRzIGFueSBpbmZvcm1hdGlvbiBhYm91dCB3aGljaCBub2RlIHdhcyAybmQgb3IgM3JkIGNsb3Nlc3QuIFRoaXMgaW5mb3JtYXRpb24gbWlnaHQgYWxzbyBiZSB1c2VmdWwgZm9yIGhlbHBpbmcgdG8gc2VlIHdoaWNoIHRleHRzIGFyZSBtb3N0IGNsb3NlbHkgcmVsYXRlZC4gRGVsdGEgZGlzdGFuY2VzICh3aXRob3V0IHByb25vdW5zKSBhcmUgdmlzdWFsaXplZCBiZWxvdyB1c2luZyBHZXBoaSAoYSBkYXRhIHZpc3VhbGl6YXRpb24gcHJvZ3JhbSkgd2l0aCB0aGUgRm9yY2VBdGxhczIgc2V0dGluZywgd2hpY2ggaGVscHMgdG8gYmV0dGVyIHZpc3VhbGl6ZSBjbHVzdGVycy4gVWx0aW1hdGVseSwgdGhpcyB2aXN1YWxpemF0aW9uIGFsbG93cyB1cyB0byBtb3JlIGVhc2lseSBzZWUgY2x1c3RlcnMsIGFuZCB3aGljaCBjbHVzdGVycyBhcmUgY2xvc2UgdG8gZWFjaCBvdGhlciwgb2YgdGV4dHMuCgpgYGB7ciBnZXBoaSwgZWNobz1GQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImdlcGhpX2RlbHRhXzIwOV9sYWJlbHMucG5nIikKYGBgCgojIENoYXB0ZXIgYW5hbHlzZXMKIyMgQ2FzZSBzdHVkeTogUGFydCAxClBhcnQgMSBvZiB0aGUgY2FzZSBzdHVkeSB3aWxsIGZvY3VzIG9uIGV4cGxhaW5pbmcgdGhlIGRpZmZlcmVuY2UgaW4gZnVuY3Rpb24gd29yZCB1c2FnZSBiZXR3ZWVuIHRoZSBodW1hbml0aWVzIGFuZCB0aGUgc2NpZW5jZXMuIFRoaXMgaXMgYSBzcGxpdCB0aGF0IHdlIHNlZSBib3RoIGluIHRoZSBuZXR3b3JrIGFuYWx5c2lzIHZpc3VhbGl6YXRpb24sIGFuZCBkZW5kcm9ncmFtcyBiYXNlZCBvbiBEZWx0YSBkaXN0YW5jZSBhYm92ZS4KCkluIG9yZGVyIHRvIGRvIHRoaXMgYW5hbHlzaXMsIHdlIGZpcnN0IGlkZW50aWZ5IHdoYXQgZnVuY3Rpb24gd29yZHMgc2VlbSB0byBjb250cmlidXRlIG1vc3QgdG8gdGhpcyBzcGxpdC4gSW4gb3RoZXIgd29yZHMsIHdoaWNoIGZ1bmN0aW9uIHdvcmRzIGFyZSBkcml2aW5nIHRoZSBsYXJnZXN0IGRpc3RhbmNlIGJldHdlZW4gaHVtYW5pdGllcyBhbmQgc2NpZW5jZSB0ZXh0cz8gVGhlbiBmb3IgdGhlc2UgZnVuY3Rpb24gd29yZHMsIHdlIGFkZCBpbmZvcm1hdGlvbiBhYm91dCBwLXZhbHVlcywgZWZmZWN0IHNpemVzLCBhbmQga2V5bmVzcy4gVGhlIHRhYmxlIGJlbG93IHNob3dzLCBmb3IgZWFjaCBmdW5jdGlvbiB3b3JkLCB0aGUgdG90YWwgb2YgaXRzIHVzYWdlIChpbiB0ZXJtcyBvZiB6LXNjb3JlcykgaW4gYm90aCB0aGUgaHVtYW5pdGllcyBhbmQgc2NpZW5jZXMuIFRoZSBkaWZmZXJlbmNlIGNvbHVtbiBzaW1wbHkgc3VidHJhY3RzIHRoZSB0d28sIGFuZCB0aGUgdGFibGUgaXMgcmFua2VkIGJ5IHRoaXMgY29sdW1uLiAKYGBge3IgY3JlYXRlIGxhcmdlIHRhYmxlIG9mIGRpc3RhbmNlcyBiZXR3ZWVuIGV2ZXJ5IHBhaXIgb2YgdGV4dHN9CiNjcmVhdGUgbWFzdGVyIGRmIGZvciBzdG9yaW5nIGRhdGEKZGlzdGFuY2VfcGllY2VzX2RmIDwtIG1hdHJpeCgwLCBucm93PTIwOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbD1ucm93KHN0eWxvX2RlbHRhX3Jlc3VsdHNfbm9wcm9ub3VucyR0YWJsZS53aXRoLmFsbC56c2NvcmVzKV4yKQoKI2NyZWF0ZSBjb2x1bW4gbmFtZXMgYXMgYSB2ZWN0b3IKY29sdW1uX25hbWVzIDwtIG91dGVyKHJvd25hbWVzKHN0eWxvX2RlbHRhX3Jlc3VsdHNfbm9wcm9ub3VucyR0YWJsZS53aXRoLmFsbC56c2NvcmVzKSwKICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKHN0eWxvX2RlbHRhX3Jlc3VsdHNfbm9wcm9ub3VucyR0YWJsZS53aXRoLmFsbC56c2NvcmVzKSwKICAgICAgICAgICAgICAgICAgICAgICJwYXN0ZSIsCiAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiWFhYIikKY29sdW1uX25hbWVzIDwtIGFzLnZlY3Rvcihjb2x1bW5fbmFtZXMpCgojY2FsY3VsYXRlIGRpc3RhbmNlcyBiZXR3ZWVuIGV2ZXJ5IHRleHQgYW5kIGFkZCB0byBtYXN0ZXIgZGYKZm9yIChmeG53b3JkIGluIDE6MjA5KSB7CiAgcm93dmFsdWVzIDwtIG91dGVyKHN0eWxvX2RlbHRhX3Jlc3VsdHNfbm9wcm9ub3VucyR0YWJsZS53aXRoLmFsbC56c2NvcmVzWyxmeG53b3JkXSwKICAgICAgICAgICAgICAgICAgICAgc3R5bG9fZGVsdGFfcmVzdWx0c19ub3Byb25vdW5zJHRhYmxlLndpdGguYWxsLnpzY29yZXNbLGZ4bndvcmRdLAogICAgICAgICAgICAgICAgICAgICAiLSIpCiAgYXR0cihyb3d2YWx1ZXMsICJkaW0iKSA8LSBwcm9kKGRpbShyb3d2YWx1ZXMpKQogIAogIGRpc3RhbmNlX3BpZWNlc19kZltmeG53b3JkLF0gPC0gcm93dmFsdWVzCiAgcHJpbnQocGFzdGUoInByb2dyZXNzIGlzICIsZnhud29yZCwiLzIwOSIsc2VwPSIiKSkKfQoKZGlzdGFuY2VfcGllY2VzX2RmIDwtIGFzLmRhdGEuZnJhbWUoYWJzKGRpc3RhbmNlX3BpZWNlc19kZikpCmNvbG5hbWVzKGRpc3RhbmNlX3BpZWNlc19kZikgPC0gY29sdW1uX25hbWVzCmRpc3RhbmNlX3BpZWNlc19kZlsiRGVsdGFfZGlzdGFuY2UiLF0gPC0gY29sU3VtcyhkaXN0YW5jZV9waWVjZXNfZGYpCgojcmVtb3ZlIGR1cGxpY2F0ZWQgY29sdW1ucwpkaXN0YW5jZV9waWVjZXNfaWRzPC1kdXBsaWNhdGVkKGFzLmxpc3QoZGlzdGFuY2VfcGllY2VzX2RmKSkKZGVsZXRlPC13aGljaChkaXN0YW5jZV9waWVjZXNfaWRzKQpkaXN0YW5jZV9waWVjZXNfZGZfdjIgPC0gZGlzdGFuY2VfcGllY2VzX2RmWywtYyhkZWxldGUpXQpkaXN0YW5jZV9waWVjZXNfZGZfdjIgPC0gZGlzdGFuY2VfcGllY2VzX2RmX3YyWywtMV0KYGBgCgpgYGB7cn0KI2tlZXAgb25seSBjb21wYXJpc29ucyBmcm9tIGVudGlyZSBjb21wYXJpc29uIHNldCB0aGF0IGFyZSBiZXR3ZWVuIGh1bWFuaXRpZXMgYW5kIHNjaWVuY2VzCmNoMV9jb21wYXJpc29uczwtYygpCmZvciAodGV4dCBpbiAxOm5jb2woZGlzdGFuY2VfcGllY2VzX2RmX3YyKSl7CiAgdGV4dDIgPC0gc3Vic3RyaW5nKHN0cmluZ3I6OnN0cl9leHRyYWN0KGNvbG5hbWVzKGRpc3RhbmNlX3BpZWNlc19kZl92MilbdGV4dF0sIlhYWC4qJCIpLDQpCiAgdGV4dDEgPC0gY29sbmFtZXMoZGlzdGFuY2VfcGllY2VzX2RmX3YyKVt0ZXh0XQogIGlmIChzdGFydHNXaXRoKHRleHQxLCJiaW8iKSB8fCBzdGFydHNXaXRoKHRleHQxLCJjcyIpfHwKICAgICAgc3RhcnRzV2l0aCh0ZXh0MSwicGh5cyIpfHwgc3RhcnRzV2l0aCh0ZXh0MSwiY2hlbWUiKXx8IAogICAgICBzdGFydHNXaXRoKHRleHQxLCJzdGF0cyIpKXsKICAgIHRleHQxX3R5cGU8LSJzY2llbmNlcyIKICB9CiAgZWxzZXsKICAgIHRleHQxX3R5cGU8LSJodW1hbml0aWVzIgogIH0KICBpZiAoc3RhcnRzV2l0aCh0ZXh0MiwiYmlvIikgfHwgc3RhcnRzV2l0aCh0ZXh0MiwiY3MiKXx8IAogICAgICBzdGFydHNXaXRoKHRleHQyLCJwaHlzIil8fCBzdGFydHNXaXRoKHRleHQyLCJjaGVtZSIpfHwgCiAgICAgIHN0YXJ0c1dpdGgodGV4dDIsInN0YXRzIikpewogICAgdGV4dDJfdHlwZTwtInNjaWVuY2VzIgogIH0KICBlbHNlewogICAgdGV4dDJfdHlwZTwtImh1bWFuaXRpZXMiCiAgfQogIGlmICh0ZXh0MV90eXBlICE9IHRleHQyX3R5cGUpewogICAgY2gxX2NvbXBhcmlzb25zPC1jKGNoMV9jb21wYXJpc29ucyx0ZXh0KQogICAgcHJpbnQodGV4dDEpCiAgfQp9CgpkaXN0YW5jZV9waWVjZXNfY2gxIDwtIGRpc3RhbmNlX3BpZWNlc19kZl92MlssY2gxX2NvbXBhcmlzb25zXQoKI2FkZCB1cCByb3dzIHRvIGNyZWF0ZSBhIHRvdGFsIGNvbHVtbgpkaXN0YW5jZV9waWVjZXNfY2gxJHRvdGFsX2Rpc3RhbmNlPC1yb3dTdW1zKGRpc3RhbmNlX3BpZWNlc19jaDEpCiNzb3J0IHdob2xlIGRmIGJ5IHRoZSB0b3RhbF9kaXN0YW5jZSBjb2x1bW4KZGlzdGFuY2VfcGllY2VzX2NoMSA8LSBkaXN0YW5jZV9waWVjZXNfY2gxW29yZGVyKGRpc3RhbmNlX3BpZWNlc19jaDEkdG90YWxfZGlzdGFuY2UsIGRlY3JlYXNpbmc9VFJVRSksXQoKI2NyZWF0ZSBkZiBmb3IgY29tcGFyaW5nCmNoMV9kZWx0YV9kZjwtZGF0YS5mcmFtZShkaXN0YW5jZV9waWVjZXNfY2gxJHRvdGFsX2Rpc3RhbmNlKQpyb3duYW1lcyhjaDFfZGVsdGFfZGYpPC1yb3duYW1lcyhkaXN0YW5jZV9waWVjZXNfY2gxKQoKI2NsZWFuIHVwIGVycm9yPz8KY2gxX3Jvd25hbWVzIDwtIHJvd25hbWVzKGNoMV9kZWx0YV9kZikKY2gxX3Jvd25hbWVzPC1zdHJpbmdyOjpzdHJfcmVwbGFjZShjaDFfcm93bmFtZXMsICJcXC4iLCAiIikKcm93bmFtZXMoY2gxX2RlbHRhX2RmKTwtY2gxX3Jvd25hbWVzCgpgYGAKCmBgYHtyIGNoMSBmeG53b3JkIGlkIGtleW5lc3MgYW5kIGVmZmVjdCBzaXplfQojZ2V0IGF2ZXJhZ2UgaHVtYW5pdGllcyBhbmQgc2NpZW5jZSBwYXBlciB6c2NvcmVzCiNjcmVhdGUgaHVtYW5pdGllcyBkYXRhZnJhbWUgb2YgenNjb3JlcwpsaWJyYXJ5KGRwbHlyKQoKI2ZpeCB3ZWlyZCBwdW5jdHVhdGlvbiBlcnJvcgpzdHlsb19jb2xuYW1lcyA8LSBjb2xuYW1lcyhzdHlsb19kZWx0YV9yZXN1bHRzX25vcHJvbm91bnMkdGFibGUud2l0aC5hbGwuenNjb3JlcykKc3R5bG9fY29sbmFtZXM8LXN0cmluZ3I6OnN0cl9yZXBsYWNlKHN0eWxvX2NvbG5hbWVzLCAiXFwuIiwgIiIpCmNvbG5hbWVzKHN0eWxvX2RlbHRhX3Jlc3VsdHNfbm9wcm9ub3VucyR0YWJsZS53aXRoLmFsbC56c2NvcmVzKTwtc3R5bG9fY29sbmFtZXMKCmh1bWFuaXRpZXNfenNjb3Jlc19kZiA8LSBhcy5kYXRhLmZyYW1lKHQoc3R5bG9fZGVsdGFfcmVzdWx0c19ub3Byb25vdW5zJHRhYmxlLndpdGguYWxsLnpzY29yZXMpKSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiZWQiKSwgc3RhcnRzX3dpdGgoInNvYyIpLHN0YXJ0c193aXRoKCJsaXQiKSxzdGFydHNfd2l0aCgiaGlzdCIpLHN0YXJ0c193aXRoKCJsaW5nIiksc3RhcnRzX3dpdGgoInBoaWwiKSxzdGFydHNfd2l0aCgicGVyZiIpLHN0YXJ0c193aXRoKCJwb2xzY2kiKSkKCiNjcmVhdGUgc2NpZW5jZXMgZGF0YWZyYW1lIG9mIHpzY29yZXMKc2NpZW5jZXNfenNjb3Jlc19kZiA8LSBhcy5kYXRhLmZyYW1lKHQoc3R5bG9fZGVsdGFfcmVzdWx0c19ub3Byb25vdW5zJHRhYmxlLndpdGguYWxsLnpzY29yZXMpKSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiY3MiKSwgc3RhcnRzX3dpdGgoInBoeXMiKSxzdGFydHNfd2l0aCgiY2hlbWUiKSxzdGFydHNfd2l0aCgic3RhdHMiKSxzdGFydHNfd2l0aCgiYmlvIikpCgojY3JlYXRlIGRmcyBmb3IgZWFjaCBkaXNjaXBsaW5lIGFuZCBhZGQgdG8gY2gxX2RlbHRhX2RmCmNzX3pzY29yZXMgPC0gYXMuZGF0YS5mcmFtZShzY2llbmNlc196c2NvcmVzX2RmKSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiY3MiKSkKY3NfenNjb3JlcyRjc19hdmVyYWdlPC1yb3dTdW1zKGNzX3pzY29yZXMpL25jb2woY3NfenNjb3JlcykKCnBoeXNfenNjb3JlcyA8LSBhcy5kYXRhLmZyYW1lKHNjaWVuY2VzX3pzY29yZXNfZGYpICU+JSBkcGx5cjo6c2VsZWN0KHN0YXJ0c193aXRoKCJwaHlzIikpCnBoeXNfenNjb3JlcyRwaHlzX2F2ZXJhZ2U8LXJvd1N1bXMocGh5c196c2NvcmVzKS9uY29sKHBoeXNfenNjb3JlcykKCmNoZW1lX3pzY29yZXMgPC0gYXMuZGF0YS5mcmFtZShzY2llbmNlc196c2NvcmVzX2RmKSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiY2hlbWUiKSkKY2hlbWVfenNjb3JlcyRjaGVtZV9hdmVyYWdlPC1yb3dTdW1zKGNoZW1lX3pzY29yZXMpL25jb2woY2hlbWVfenNjb3JlcykKCnN0YXRzX3pzY29yZXMgPC0gYXMuZGF0YS5mcmFtZShzY2llbmNlc196c2NvcmVzX2RmKSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgic3RhdHMiKSkKc3RhdHNfenNjb3JlcyRzdGF0c19hdmVyYWdlPC1yb3dTdW1zKHN0YXRzX3pzY29yZXMpL25jb2woc3RhdHNfenNjb3JlcykKCmJpb196c2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUoc2NpZW5jZXNfenNjb3Jlc19kZikgJT4lIGRwbHlyOjpzZWxlY3Qoc3RhcnRzX3dpdGgoImJpbyIpKQpiaW9fenNjb3JlcyRiaW9fYXZlcmFnZTwtcm93U3VtcyhiaW9fenNjb3JlcykvbmNvbChiaW9fenNjb3JlcykKCmVkX3pzY29yZXMgPC0gYXMuZGF0YS5mcmFtZShodW1hbml0aWVzX3pzY29yZXNfZGYpICU+JSBkcGx5cjo6c2VsZWN0KHN0YXJ0c193aXRoKCJlZCIpKQplZF96c2NvcmVzJGVkX2F2ZXJhZ2U8LXJvd1N1bXMoZWRfenNjb3JlcykvbmNvbChlZF96c2NvcmVzKQoKc29jX3pzY29yZXMgPC0gYXMuZGF0YS5mcmFtZShodW1hbml0aWVzX3pzY29yZXNfZGYpICU+JSBkcGx5cjo6c2VsZWN0KHN0YXJ0c193aXRoKCJzb2MiKSkKc29jX3pzY29yZXMkc29jX2F2ZXJhZ2U8LXJvd1N1bXMoc29jX3pzY29yZXMpL25jb2woc29jX3pzY29yZXMpCgpsaXRfenNjb3JlcyA8LSBhcy5kYXRhLmZyYW1lKGh1bWFuaXRpZXNfenNjb3Jlc19kZikgJT4lIGRwbHlyOjpzZWxlY3Qoc3RhcnRzX3dpdGgoImxpdCIpKQpsaXRfenNjb3JlcyRsaXRfYXZlcmFnZTwtcm93U3VtcyhsaXRfenNjb3JlcykvbmNvbChsaXRfenNjb3JlcykKCmhpc3RfenNjb3JlcyA8LSBhcy5kYXRhLmZyYW1lKGh1bWFuaXRpZXNfenNjb3Jlc19kZikgJT4lIGRwbHlyOjpzZWxlY3Qoc3RhcnRzX3dpdGgoImhpc3QiKSkKaGlzdF96c2NvcmVzJGhpc3RfYXZlcmFnZTwtcm93U3VtcyhoaXN0X3pzY29yZXMpL25jb2woaGlzdF96c2NvcmVzKQoKbGluZ196c2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUoaHVtYW5pdGllc196c2NvcmVzX2RmKSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgibGluZyIpKQpsaW5nX3pzY29yZXMkbGluZ19hdmVyYWdlPC1yb3dTdW1zKGxpbmdfenNjb3JlcykvbmNvbChsaW5nX3pzY29yZXMpCgpwaGlsX3pzY29yZXMgPC0gYXMuZGF0YS5mcmFtZShodW1hbml0aWVzX3pzY29yZXNfZGYpICU+JSBkcGx5cjo6c2VsZWN0KHN0YXJ0c193aXRoKCJwaGlsIikpCnBoaWxfenNjb3JlcyRwaGlsX2F2ZXJhZ2U8LXJvd1N1bXMocGhpbF96c2NvcmVzKS9uY29sKHBoaWxfenNjb3JlcykKCnBvbHNjaV96c2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUoaHVtYW5pdGllc196c2NvcmVzX2RmKSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgicG9sc2NpIikpCnBvbHNjaV96c2NvcmVzJHBvbHNjaV9hdmVyYWdlPC1yb3dTdW1zKHBvbHNjaV96c2NvcmVzKS9uY29sKHBvbHNjaV96c2NvcmVzKQoKcGVyZl96c2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUoaHVtYW5pdGllc196c2NvcmVzX2RmKSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgicGVyZiIpKQpwZXJmX3pzY29yZXMkcGVyZl9hdmVyYWdlPC1yb3dTdW1zKHBlcmZfenNjb3JlcykvbmNvbChwZXJmX3pzY29yZXMpCgojYWRkIGF2ZXJhZ2UgY29sdW1ucyB0byBib3RoIGh1bWFuaXRpZXMgYW5kIHNjaWVuY2VzIHpzY29yZXMgZGZzCmh1bWFuaXRpZXNfenNjb3Jlc19kZiRodW1hbml0aWVzX2F2ZXJhZ2U8LXJvd1N1bXMoaHVtYW5pdGllc196c2NvcmVzX2RmKS9uY29sKGh1bWFuaXRpZXNfenNjb3Jlc19kZikKc2NpZW5jZXNfenNjb3Jlc19kZiRzY2llbmNlc19hdmVyYWdlPC1yb3dTdW1zKHNjaWVuY2VzX3pzY29yZXNfZGYpL25jb2woc2NpZW5jZXNfenNjb3Jlc19kZikKCiNhZGQgYXZlcmFnZSBjb2x1bW5zIHRvIGNoMV9kZWx0YV9kZgpjaDFfZGVsdGFfZGY8LW1lcmdlKGNoMV9kZWx0YV9kZixkcGx5cjo6c2VsZWN0KGh1bWFuaXRpZXNfenNjb3Jlc19kZixuY29sKGh1bWFuaXRpZXNfenNjb3Jlc19kZikpLGJ5PSJyb3cubmFtZXMiKQpjaDFfZGVsdGFfZGYgPC0gZGF0YS5mcmFtZShjaDFfZGVsdGFfZGYsIHJvdy5uYW1lcz0xKQpjaDFfZGVsdGFfZGY8LW1lcmdlKGNoMV9kZWx0YV9kZixkcGx5cjo6c2VsZWN0KHNjaWVuY2VzX3pzY29yZXNfZGYsbmNvbChzY2llbmNlc196c2NvcmVzX2RmKSksYnk9InJvdy5uYW1lcyIpCmNoMV9kZWx0YV9kZiA8LSBkYXRhLmZyYW1lKGNoMV9kZWx0YV9kZiwgcm93Lm5hbWVzPTEpCgpjaDFfZGVsdGFfZGY8LW1lcmdlKGNoMV9kZWx0YV9kZixkcGx5cjo6c2VsZWN0KGNzX3pzY29yZXMsbmNvbChjc196c2NvcmVzKSksYnk9InJvdy5uYW1lcyIpCmNoMV9kZWx0YV9kZiA8LSBkYXRhLmZyYW1lKGNoMV9kZWx0YV9kZiwgcm93Lm5hbWVzPTEpCmNoMV9kZWx0YV9kZjwtbWVyZ2UoY2gxX2RlbHRhX2RmLGRwbHlyOjpzZWxlY3QoYmlvX3pzY29yZXMsbmNvbChiaW9fenNjb3JlcykpLGJ5PSJyb3cubmFtZXMiKQpjaDFfZGVsdGFfZGYgPC0gZGF0YS5mcmFtZShjaDFfZGVsdGFfZGYsIHJvdy5uYW1lcz0xKQpjaDFfZGVsdGFfZGY8LW1lcmdlKGNoMV9kZWx0YV9kZixkcGx5cjo6c2VsZWN0KGNoZW1lX3pzY29yZXMsbmNvbChjaGVtZV96c2NvcmVzKSksYnk9InJvdy5uYW1lcyIpCmNoMV9kZWx0YV9kZiA8LSBkYXRhLmZyYW1lKGNoMV9kZWx0YV9kZiwgcm93Lm5hbWVzPTEpCmNoMV9kZWx0YV9kZjwtbWVyZ2UoY2gxX2RlbHRhX2RmLGRwbHlyOjpzZWxlY3QocGh5c196c2NvcmVzLG5jb2wocGh5c196c2NvcmVzKSksYnk9InJvdy5uYW1lcyIpCmNoMV9kZWx0YV9kZiA8LSBkYXRhLmZyYW1lKGNoMV9kZWx0YV9kZiwgcm93Lm5hbWVzPTEpCmNoMV9kZWx0YV9kZjwtbWVyZ2UoY2gxX2RlbHRhX2RmLGRwbHlyOjpzZWxlY3Qoc3RhdHNfenNjb3JlcyxuY29sKHN0YXRzX3pzY29yZXMpKSxieT0icm93Lm5hbWVzIikKY2gxX2RlbHRhX2RmIDwtIGRhdGEuZnJhbWUoY2gxX2RlbHRhX2RmLCByb3cubmFtZXM9MSkKY2gxX2RlbHRhX2RmPC1tZXJnZShjaDFfZGVsdGFfZGYsZHBseXI6OnNlbGVjdChlZF96c2NvcmVzLG5jb2woZWRfenNjb3JlcykpLGJ5PSJyb3cubmFtZXMiKQpjaDFfZGVsdGFfZGYgPC0gZGF0YS5mcmFtZShjaDFfZGVsdGFfZGYsIHJvdy5uYW1lcz0xKQpjaDFfZGVsdGFfZGY8LW1lcmdlKGNoMV9kZWx0YV9kZixkcGx5cjo6c2VsZWN0KGhpc3RfenNjb3JlcyxuY29sKGhpc3RfenNjb3JlcykpLGJ5PSJyb3cubmFtZXMiKQpjaDFfZGVsdGFfZGYgPC0gZGF0YS5mcmFtZShjaDFfZGVsdGFfZGYsIHJvdy5uYW1lcz0xKQpjaDFfZGVsdGFfZGY8LW1lcmdlKGNoMV9kZWx0YV9kZixkcGx5cjo6c2VsZWN0KGxpbmdfenNjb3JlcyxuY29sKGxpbmdfenNjb3JlcykpLGJ5PSJyb3cubmFtZXMiKQpjaDFfZGVsdGFfZGYgPC0gZGF0YS5mcmFtZShjaDFfZGVsdGFfZGYsIHJvdy5uYW1lcz0xKQpjaDFfZGVsdGFfZGY8LW1lcmdlKGNoMV9kZWx0YV9kZixkcGx5cjo6c2VsZWN0KGxpdF96c2NvcmVzLG5jb2wobGl0X3pzY29yZXMpKSxieT0icm93Lm5hbWVzIikKY2gxX2RlbHRhX2RmIDwtIGRhdGEuZnJhbWUoY2gxX2RlbHRhX2RmLCByb3cubmFtZXM9MSkKY2gxX2RlbHRhX2RmPC1tZXJnZShjaDFfZGVsdGFfZGYsZHBseXI6OnNlbGVjdChwZXJmX3pzY29yZXMsbmNvbChwZXJmX3pzY29yZXMpKSxieT0icm93Lm5hbWVzIikKY2gxX2RlbHRhX2RmIDwtIGRhdGEuZnJhbWUoY2gxX2RlbHRhX2RmLCByb3cubmFtZXM9MSkKY2gxX2RlbHRhX2RmPC1tZXJnZShjaDFfZGVsdGFfZGYsZHBseXI6OnNlbGVjdChwaGlsX3pzY29yZXMsbmNvbChwaGlsX3pzY29yZXMpKSxieT0icm93Lm5hbWVzIikKY2gxX2RlbHRhX2RmIDwtIGRhdGEuZnJhbWUoY2gxX2RlbHRhX2RmLCByb3cubmFtZXM9MSkKY2gxX2RlbHRhX2RmPC1tZXJnZShjaDFfZGVsdGFfZGYsZHBseXI6OnNlbGVjdChzb2NfenNjb3JlcyxuY29sKHNvY196c2NvcmVzKSksYnk9InJvdy5uYW1lcyIpCmNoMV9kZWx0YV9kZiA8LSBkYXRhLmZyYW1lKGNoMV9kZWx0YV9kZiwgcm93Lm5hbWVzPTEpCmNoMV9kZWx0YV9kZjwtbWVyZ2UoY2gxX2RlbHRhX2RmLGRwbHlyOjpzZWxlY3QocG9sc2NpX3pzY29yZXMsbmNvbChwb2xzY2lfenNjb3JlcykpLGJ5PSJyb3cubmFtZXMiKQpjaDFfZGVsdGFfZGYgPC0gZGF0YS5mcmFtZShjaDFfZGVsdGFfZGYsIHJvdy5uYW1lcz0xKQoKI2FkZCBjb2x1bW4gc2F5aW5nIHdoZXRoZXIgd29yZCBpcyBtb3JlIHByb21pbmVudCBpbiBodW1hbml0aWVzIG9yIHNjaWVuY2VzCmZvciAociBpbiAxOm5yb3coY2gxX2RlbHRhX2RmKSl7CiAgaWYgKGNoMV9kZWx0YV9kZiRodW1hbml0aWVzX2F2ZXJhZ2Vbcl0gPiBjaDFfZGVsdGFfZGYkc2NpZW5jZXNfYXZlcmFnZVtyXSl7CiAgICBjaDFfZGVsdGFfZGYkZGlzY2lwbGluZVtyXSA8LSAiaHVtYW5pdGllcyIKICB9IGVsc2UgewogICAgY2gxX2RlbHRhX2RmJGRpc2NpcGxpbmVbcl0gPC0gInNjaWVuY2VzIgogIH0KfQoKI2NyZWF0ZSBkZm0gZ3JvdXBlZCBieSBkaXNjaXBsaW5lCmtleW5lc3NfY2gxX2RmbSA8LSBkZm1fZ3JvdXAocmF3dG9rZW5zX2RmbSwgZ3JvdXBzPSJjaDEiKQpjaDFfdmVjdG9yIDwtIHVuaXF1ZShtZXRhZGF0YSRjaDEpCgojY3JlYXRlIGxpc3QgdG8gc3RvcmUgdmFsdWVzIGluIGFuZCBkYXRhIGZyYW1lIHRvIHByaW50CmtleXdvcmRzX2NoMSA8LSBsaXN0KCkKa2V5d29yZF90YWJsZV9jaDEgPC0gZGF0YS5mcmFtZSgpCiNsb29wIHRocm91Z2ggZGlzY2lwbGluZXMgYW5kIHN0b3JlIHZhbHVlcyBpbiBrZXl3b3JkcyBsaXN0CmZvciAoaSBpbiAxOmxlbmd0aChjaDFfdmVjdG9yKSkgewogICNnZXQga2V5d29yZHMKICBrZXl3b3Jkc19jaDFbW2NoMV92ZWN0b3JbaV1dXSA8LSB0ZXh0c3RhdF9rZXluZXNzKGtleW5lc3NfY2gxX2RmbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0PWNoMV92ZWN0b3JbaV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUgPSAibHIiKQogICNhZGQgZWZmZWN0IHNpemUKICBrZXl3b3Jkc19jaDFbW2NoMV92ZWN0b3JbaV1dXSA8LSBrZXl3b3Jkc19jaDFbW2NoMV92ZWN0b3JbaV1dXSAlPiUgCiAgICBkcGx5cjo6bXV0YXRlKC4sIGVmZmVjdCA9IGVmZmVjdF9zaXplKG5fdGFyZ2V0LCBuX3JlZmVyZW5jZSkpCiAgI3Rha2UgYXdheSB0YXJnZXQgYW5kIHJlZmVyZW5jZSBjb3VudHMKICBwciA8LSBkcGx5cjo6c2VsZWN0KGtleXdvcmRzX2NoMVtbY2gxX3ZlY3RvcltpXV1dLCAtbl90YXJnZXQsIC1uX3JlZmVyZW5jZSkKICAjcmVuYW1lIGNvbHVtbnMKICBuYW1lcyhwcilbMl0gPC0gJ2tleW5lc3MnCiAgbmFtZXMocHIpWzNdIDwtICdwLXZhbHVlJwogIG5hbWVzKHByKVs0XSA8LSAnZWZmZWN0IHNpemUnCiAgI2FwcGVuZCB0byB0YWJsZSBmb3IgcHJpbnRpbmcgJiBzYXZlIGRpc2NpcGxpbmUgbmFtZQogIGtleXdvcmRfdGFibGVfY2gxIDwtIHJiaW5kKGtleXdvcmRfdGFibGVfY2gxLCBwcikKfQoKI2Fzc2lnbiByb3duYW1lcyB0byBkYXRhCmtleXdvcmRzX2NoMVtbImh1bWFuaXRpZXMiXV0gPC0gZGF0YS5mcmFtZShrZXl3b3Jkc19jaDFbWyJodW1hbml0aWVzIl1dWywtMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0ga2V5d29yZHNfY2gxW1siaHVtYW5pdGllcyJdXVssMV0pCmtleXdvcmRzX2NoMVtbInNjaWVuY2VzIl1dIDwtIGRhdGEuZnJhbWUoa2V5d29yZHNfY2gxW1sic2NpZW5jZXMiXV1bLC0xXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBrZXl3b3Jkc19jaDFbWyJzY2llbmNlcyJdXVssMV0pCgojYWRkIGtleW5lc3MgaW5mbyB0byBjaDFfZGVsdGFfZGYKZm9yIChpIGluIDE6bnJvdyhjaDFfZGVsdGFfZGYpKXsKICB3b3JkIDwtIHJvd25hbWVzKGNoMV9kZWx0YV9kZilbaV0KICBpZiAoY2gxX2RlbHRhX2RmJGRpc2NpcGxpbmVbaV0gPT0gInNjaWVuY2VzIil7CiAgICBrZXluZXNzID0ga2V5d29yZHNfY2gxW1sic2NpZW5jZXMiXV1bd29yZCwiRzIiXQogICAgZWZmZWN0ID0ga2V5d29yZHNfY2gxW1sic2NpZW5jZXMiXV1bd29yZCwiZWZmZWN0Il0KICAgIHB2YWx1ZSA9IGtleXdvcmRzX2NoMVtbInNjaWVuY2VzIl1dW3dvcmQsInAiXQogICAgY2gxX2RlbHRhX2RmJGtleW5lc3NbaV0gPC0ga2V5bmVzcwogICAgY2gxX2RlbHRhX2RmJGVmZmVjdF9zaXplW2ldIDwtIGVmZmVjdAogICAgY2gxX2RlbHRhX2RmJHBfdmFsdWVbaV0gPC0gcHZhbHVlCiAgfQogIGVsc2UgewogICAga2V5bmVzcyA9IGtleXdvcmRzX2NoMVtbImh1bWFuaXRpZXMiXV1bd29yZCwiRzIiXQogICAgZWZmZWN0ID0ga2V5d29yZHNfY2gxW1siaHVtYW5pdGllcyJdXVt3b3JkLCJlZmZlY3QiXQogICAgcHZhbHVlID0ga2V5d29yZHNfY2gxW1siaHVtYW5pdGllcyJdXVt3b3JkLCJwIl0KICAgIGNoMV9kZWx0YV9kZiRrZXluZXNzW2ldIDwtIGtleW5lc3MKICAgIGNoMV9kZWx0YV9kZiRlZmZlY3Rfc2l6ZVtpXSA8LSBlZmZlY3QKICAgIGNoMV9kZWx0YV9kZiRwX3ZhbHVlW2ldIDwtIHB2YWx1ZQogIH0KfQoKI2NsZWFuIHVwIHRhYmxlIGNvbHVtbiBuYW1lcyBhbmQgbWFrZSBkaXN0YW5jZSBwcm9wb3J0aW9uYWwgdG8gRGVsdGEKY29sbmFtZXMoY2gxX2RlbHRhX2RmKVsxXTwtIkRlbHRhX2Rpc3RhbmNlIgpjaDFfZGVsdGFfZGYkRGVsdGFfZGlzdGFuY2U8LWNoMV9kZWx0YV9kZiREZWx0YV9kaXN0YW5jZS9ucm93KGNoMV9kZWx0YV9kZikKCiNwcmludCBzYW1wbGUKcHJpbnQoaGVhZChjaDFfZGVsdGFfZGYpKQpgYGAKCkZpbmFsbHksIHRoZSB0YWJsZXMgY3JlYXRlZCBiZWxvdyBzaG93IGVhY2gga2V5d29yZCBpbiBjb250ZXh0IGZvciBldmVyeSB0ZXh0LiBTYW1wbGVzIGFyZSBzaG93biBiZWxvdy4gQSBwYXJ0aWN1bGFyIGtleXdvcmQncyB1c2FnZSBpbiBlaXRoZXIgdGhlIGh1bWFuaXRpZXMgb3Igc2NpZW5jZXMgY2FuIGJlIGFjY2Vzc2VkIHdpdGggc2NpZW5jZXNfa3dpY1tbJ3RoZSddXS4gQSBwYXJ0aWN1bGFyIGtleXdvcmQncyB1c2FnZSBpbiBhIHBhcnRpY3VsYXIgcGFwZXIgY2FuIGJlIGFjY2Vzc2VkIHdpdGggc2NpZW5jZXNfa3dpY1tbJ3RoZSddXVtzY2llbmNlc19rd2ljW1sndGhlJ11dJGRvY25hbWUgPT0gJ2NzX2N2cHJfMjAxN18xLnR4dCcsXS4KYGBge3Iga3dpYyBjaDEsIG1lc3NhZ2U9RkFMU0V9CiNjcmVhdGUgaHVtYW5pdGllcyBhbmQgc2NpZW5jZXMgc3ViLWNvcnBvcmEKaHVtYW5pdGllc19jb3JwdXMgPC0gY29ycHVzX3N1YnNldChmdWxsX2NvcnB1cywgRGlzY19zaG9ydCA9PSAiZWQiIHwgRGlzY19zaG9ydCA9PSAibGl0IiB8IERpc2Nfc2hvcnQgPT0gInBlcmYiIHwgRGlzY19zaG9ydCA9PSAibGluZyIgfCBEaXNjX3Nob3J0ID09ICJwaGlsIiB8IERpc2Nfc2hvcnQgPT0gInNvYyIgfCBEaXNjX3Nob3J0ID09ICJwb2xzY2kiIHwgRGlzY19zaG9ydCA9PSAiaGlzdCIpCnNjaWVuY2VzX2NvcnB1cyA8LSBjb3JwdXNfc3Vic2V0KGZ1bGxfY29ycHVzLCBEaXNjX3Nob3J0ID09ICJjaGVtZSIgfCBEaXNjX3Nob3J0ID09ICJjcyIgfCBEaXNjX3Nob3J0ID09ICJwaHlzIiB8IERpc2Nfc2hvcnQgPT0gInN0YXRzIiB8IERpc2Nfc2hvcnQgPT0gImJpbyIpCgojY3JlYXRlIGt3aWMgbGlzdHMKaHVtYW5pdGllc19rd2ljIDwtIGxpc3QoKQpzY2llbmNlc19rd2ljIDwtIGxpc3QoKQpmb3IgKHdvcmQgaW4gMToyMDkpIHsKICBmeG53b3JkIDwtIHJvd25hbWVzKGNoMV9kZilbd29yZF0KICBoPC1rd2ljKGh1bWFuaXRpZXNfY29ycHVzLCBmeG53b3JkLCB3aW5kb3cgPSAxMiwgd2hvbGV3b3JkPVRSVUUpCiAgczwta3dpYyhzY2llbmNlc19jb3JwdXMsIGZ4bndvcmQsIHdpbmRvdyA9IDEyLCB3aG9sZXdvcmQ9VFJVRSkKICBodW1hbml0aWVzX2t3aWNbW2Z4bndvcmRdXTwtaAogIHNjaWVuY2VzX2t3aWNbW2Z4bndvcmRdXTwtcwp9CgpwcmludChoZWFkKHNjaWVuY2VzX2t3aWNbWyd0aGUnXV1bc2NpZW5jZXNfa3dpY1tbJ3RoZSddXSRkb2NuYW1lID09ICdjc19jdnByXzIwMTdfMS50eHQnLF0pKQpwcmludChoZWFkKGh1bWFuaXRpZXNfa3dpY1tbJ3RoZSddXVtodW1hbml0aWVzX2t3aWNbWyd0aGUnXV0kZG9jbmFtZSA9PSAncGVyZl90ZHJfMjAxN18xLnR4dCcsXSkpCmBgYAoKIyMgQ2FzZSBzdHVkeTogUGFydCAyClRoZSB0YWJsZSBwcmV2aWV3IGJlbG93IHNob3dzIHdoaWNoIGZ1bmN0aW9uIHdvcmRzIGNvbnRyaWJ1dGUgdG8gdGhlIHNwcmVhZCB3aXRoaW4gdGhlIHNjaWVuY2VzIGFuZCBodW1hbml0aWVzLCByZXNwZWN0aXZlbHkuIEluIHBhcnRpY3VsYXIsIHRoZSB0YWJsZSBiZWxvdyBzaG93cyB3aGljaCB3b3JkcyBjb250cmlidXRlIG1vc3QgdG8gdGhlIGRpc3RhbmNlIGJldHdlZW4gY29tcHV0ZXIgc2NpZW5jZSBhbmQgY2VsbCAmIG1vbGVjdWxhciBiaW9sb2d5LCBhbmQgcGhpbG9zb3BoeSBhbmQgaGlzdG9yeS4gSXQgYWxzbyBpbmNsdWRlcyBhdmVyYWdlcyBmb3IgZWFjaCBkaXNjaXBsaW5lIG9uIGVhY2ggZnVuY3Rpb24gd29yZCwgYXMgd2VsbCBhcyBwLXZhbHVlcywgZWZmZWN0IHNpemVzLCBhbmQgbG9nLWxpa2VsaWhvb2QgdmFsdWVzLgpgYGB7ciBjaGFwdGVyIDIgYW5hbHlzaXN9CiNzY2llbmNlcwoja2VlcCBvbmx5IGNvbXBhcmlzb25zIGJldHdlZW4gY3MgYW5kIGJpbwpjaDJfY29tcGFyaXNvbnM8LWMoKQpmb3IgKHRleHQgaW4gMTpuY29sKGRpc3RhbmNlX3BpZWNlc19kZl92MikpewogIHRleHQyIDwtIHN1YnN0cmluZyhzdHJpbmdyOjpzdHJfZXh0cmFjdChjb2xuYW1lcyhkaXN0YW5jZV9waWVjZXNfZGZfdjIpW3RleHRdLCJYWFguKiQiKSw0KQogIHRleHQxIDwtIGNvbG5hbWVzKGRpc3RhbmNlX3BpZWNlc19kZl92MilbdGV4dF0KICBpZiAoc3RhcnRzV2l0aCh0ZXh0MSwiYmlvIikpewogICAgdGV4dDFfdHlwZTwtImJpbyIKICB9IGVsc2UgaWYgKHN0YXJ0c1dpdGgodGV4dDEsImNzIikpewogICAgdGV4dDFfdHlwZTwtImNzIgogIH0gZWxzZSB7CiAgICB0ZXh0MV90eXBlPC0ib3RoZXIiCiAgfSAKICBpZiAoc3RhcnRzV2l0aCh0ZXh0MiwiYmlvIikpewogICAgdGV4dDJfdHlwZTwtImJpbyIKICB9IGVsc2UgaWYgKHN0YXJ0c1dpdGgodGV4dDIsImNzIikpewogICAgdGV4dDJfdHlwZTwtImNzIgogIH0gZWxzZSB7CiAgICB0ZXh0Ml90eXBlPC0ib3RoZXIiCiAgfSAKICBpZiAodGV4dDFfdHlwZSA9PSAiYmlvIiAmJiB0ZXh0Ml90eXBlID09ICJjcyIgfHwgdGV4dDFfdHlwZSA9PSAiY3MiICYmIHRleHQyX3R5cGUgPT0iYmlvIil7CiAgICBjaDJfY29tcGFyaXNvbnM8LWMoY2gyX2NvbXBhcmlzb25zLHRleHQpCiAgICBwcmludCh0ZXh0MSkKICB9Cn0KCmRpc3RhbmNlX3BpZWNlc19zY2llbmNlc19jaDIgPC0gZGlzdGFuY2VfcGllY2VzX2RmX3YyWyxjaDJfY29tcGFyaXNvbnNdCgojYWRkIHVwIHJvd3MgdG8gY3JlYXRlIGEgdG90YWwgY29sdW1uCmRpc3RhbmNlX3BpZWNlc19zY2llbmNlc19jaDIkdG90YWxfZGlzdGFuY2U8LXJvd1N1bXMoZGlzdGFuY2VfcGllY2VzX3NjaWVuY2VzX2NoMikKI3NvcnQgd2hvbGUgZGYgYnkgdGhlIHRvdGFsX2Rpc3RhbmNlIGNvbHVtbgpkaXN0YW5jZV9waWVjZXNfc2NpZW5jZXNfY2gyIDwtIGRpc3RhbmNlX3BpZWNlc19zY2llbmNlc19jaDJbb3JkZXIoZGlzdGFuY2VfcGllY2VzX3NjaWVuY2VzX2NoMiR0b3RhbF9kaXN0YW5jZSwgZGVjcmVhc2luZz1UUlVFKSxdCgojY3JlYXRlIGRmIGZvciBjb21wYXJpbmcKY2gyX3NjaWVuY2VzX2RmPC1kYXRhLmZyYW1lKGRpc3RhbmNlX3BpZWNlc19zY2llbmNlc19jaDIkdG90YWxfZGlzdGFuY2UpCnJvd25hbWVzKGNoMl9zY2llbmNlc19kZik8LXJvd25hbWVzKGRpc3RhbmNlX3BpZWNlc19zY2llbmNlc19jaDIpCgojaHVtYW5pdGllcwoja2VlcCBvbmx5IGNvbXBhcmlzb25zIGJldHdlZW4gcGhpbCAmIGhpc3QKY2gyX2NvbXBhcmlzb25zX2h1bTwtYygpCmZvciAodGV4dCBpbiAxOm5jb2woZGlzdGFuY2VfcGllY2VzX2RmX3YyKSl7CiAgdGV4dDIgPC0gc3Vic3RyaW5nKHN0cmluZ3I6OnN0cl9leHRyYWN0KGNvbG5hbWVzKGRpc3RhbmNlX3BpZWNlc19kZl92MilbdGV4dF0sIlhYWC4qJCIpLDQpCiAgdGV4dDEgPC0gY29sbmFtZXMoZGlzdGFuY2VfcGllY2VzX2RmX3YyKVt0ZXh0XQogIGlmIChzdGFydHNXaXRoKHRleHQxLCJoaXN0IikpewogICAgdGV4dDFfdHlwZTwtImhpc3QiCiAgfSBlbHNlIGlmIChzdGFydHNXaXRoKHRleHQxLCJwaGlsIikpewogICAgdGV4dDFfdHlwZTwtInBoaWwiCiAgfSBlbHNlIHsKICAgIHRleHQxX3R5cGU8LSJvdGhlciIKICB9IAogIGlmIChzdGFydHNXaXRoKHRleHQyLCJoaXN0IikpewogICAgdGV4dDJfdHlwZTwtImhpc3QiCiAgfSBlbHNlIGlmIChzdGFydHNXaXRoKHRleHQyLCJwaGlsIikpewogICAgdGV4dDJfdHlwZTwtInBoaWwiCiAgfSBlbHNlIHsKICAgIHRleHQyX3R5cGU8LSJvdGhlciIKICB9IAogIGlmICh0ZXh0MV90eXBlID09ICJoaXN0IiAmJiB0ZXh0Ml90eXBlID09ICJwaGlsIiB8fCB0ZXh0MV90eXBlID09ICJwaGlsIiAmJiB0ZXh0Ml90eXBlID09Imhpc3QiKXsKICAgIGNoMl9jb21wYXJpc29uc19odW08LWMoY2gyX2NvbXBhcmlzb25zX2h1bSx0ZXh0KQogIH0KfQoKZGlzdGFuY2VfcGllY2VzX2h1bV9jaDIgPC0gZGlzdGFuY2VfcGllY2VzX2RmX3YyWyxjaDJfY29tcGFyaXNvbnNfaHVtXQoKI2FkZCB1cCByb3dzIHRvIGNyZWF0ZSBhIHRvdGFsIGNvbHVtbgpkaXN0YW5jZV9waWVjZXNfaHVtX2NoMiR0b3RhbF9kaXN0YW5jZTwtcm93U3VtcyhkaXN0YW5jZV9waWVjZXNfaHVtX2NoMikKI3NvcnQgd2hvbGUgZGYgYnkgdGhlIHRvdGFsX2Rpc3RhbmNlIGNvbHVtbgpkaXN0YW5jZV9waWVjZXNfaHVtX2NoMiA8LSBkaXN0YW5jZV9waWVjZXNfaHVtX2NoMltvcmRlcihkaXN0YW5jZV9waWVjZXNfaHVtX2NoMiR0b3RhbF9kaXN0YW5jZSwgZGVjcmVhc2luZz1UUlVFKSxdCgojY3JlYXRlIGRmIGZvciBjb21wYXJpbmcKY2gyX2h1bV9kZjwtZGF0YS5mcmFtZShkaXN0YW5jZV9waWVjZXNfaHVtX2NoMiR0b3RhbF9kaXN0YW5jZSkKcm93bmFtZXMoY2gyX2h1bV9kZik8LXJvd25hbWVzKGRpc3RhbmNlX3BpZWNlc19odW1fY2gyKQpgYGAKCmBgYCB7cn0KI2FkZCBhdmVyYWdlcwojc2NpZW5jZXMKY2gyX3NjaWVuY2VzX2RmPC1tZXJnZShjaDJfc2NpZW5jZXNfZGYsZHBseXI6OnNlbGVjdChjc196c2NvcmVzLG5jb2woY3NfenNjb3JlcykpLGJ5PSJyb3cubmFtZXMiKQpjaDJfc2NpZW5jZXNfZGYgPC0gZGF0YS5mcmFtZShjaDJfc2NpZW5jZXNfZGYsIHJvdy5uYW1lcz0xKQpjaDJfc2NpZW5jZXNfZGY8LW1lcmdlKGNoMl9zY2llbmNlc19kZixkcGx5cjo6c2VsZWN0KGJpb196c2NvcmVzLG5jb2woYmlvX3pzY29yZXMpKSxieT0icm93Lm5hbWVzIikKY2gyX3NjaWVuY2VzX2RmIDwtIGRhdGEuZnJhbWUoY2gyX3NjaWVuY2VzX2RmLCByb3cubmFtZXM9MSkKI2h1bWFuaXRpZXMKY2gyX2h1bV9kZjwtbWVyZ2UoY2gyX2h1bV9kZixkcGx5cjo6c2VsZWN0KGhpc3RfenNjb3JlcyxuY29sKGhpc3RfenNjb3JlcykpLGJ5PSJyb3cubmFtZXMiKQpjaDJfaHVtX2RmIDwtIGRhdGEuZnJhbWUoY2gyX2h1bV9kZiwgcm93Lm5hbWVzPTEpCmNoMl9odW1fZGY8LW1lcmdlKGNoMl9odW1fZGYsZHBseXI6OnNlbGVjdChwaGlsX3pzY29yZXMsbmNvbChwaGlsX3pzY29yZXMpKSxieT0icm93Lm5hbWVzIikKY2gyX2h1bV9kZiA8LSBkYXRhLmZyYW1lKGNoMl9odW1fZGYsIHJvdy5uYW1lcz0xKQoKI2FkZCBjb2x1bW4gc2F5aW5nIHdoaWNoIGRpc2NpcGxpbmUgd29yZCBpcyBtb3JlIHByb21pbmVudCBpbgojc2NpZW5jZXMKZm9yIChyIGluIDE6bnJvdyhjaDJfc2NpZW5jZXNfZGYpKXsKICBpZiAoY2gyX3NjaWVuY2VzX2RmJGNzX2F2ZXJhZ2Vbcl0gPiBjaDJfc2NpZW5jZXNfZGYkYmlvX2F2ZXJhZ2Vbcl0pewogICAgY2gyX3NjaWVuY2VzX2RmJGRpc2NpcGxpbmVbcl0gPC0gImNzIgogIH0gZWxzZSB7CiAgICBjaDJfc2NpZW5jZXNfZGYkZGlzY2lwbGluZVtyXSA8LSAiYmlvIgogIH0KfQojaHVtYW5pdGllcwpmb3IgKHIgaW4gMTpucm93KGNoMl9odW1fZGYpKXsKICBpZiAoY2gyX2h1bV9kZiRwaGlsX2F2ZXJhZ2Vbcl0gPiBjaDJfaHVtX2RmJGhpc3RfYXZlcmFnZVtyXSl7CiAgICBjaDJfaHVtX2RmJGRpc2NpcGxpbmVbcl0gPC0gInBoaWwiCiAgfSBlbHNlIHsKICAgIGNoMl9odW1fZGYkZGlzY2lwbGluZVtyXSA8LSAiaGlzdCIKICB9Cn0KCiNzY2llbmNlcwojY3JlYXRlIGRmbSBncm91cGVkIGJ5IGRpc2NpcGxpbmUKY2gyX2NzX2NvcnB1czwtY29ycHVzX3N1YnNldChmdWxsX2NvcnB1cywgRGlzY19zaG9ydCA9PSAiY3MiKQpjaDJfYmlvX2NvcnB1czwtY29ycHVzX3N1YnNldChmdWxsX2NvcnB1cywgRGlzY19zaG9ydCA9PSAiYmlvIikKY2gyX3NjaWVuY2VfY29ycHVzPC1jKGNoMl9jc19jb3JwdXMsY2gyX2Jpb19jb3JwdXMpCgojQ291bnQgdG9rZW5zIGluIGVhY2ggdGV4dApjaDJzY2lfdG9rZW5zIDwtIHRva2VucyhjaDJfc2NpZW5jZV9jb3JwdXMsIGluY2x1ZGVfZG9jdmFycz1UUlVFLCByZW1vdmVfcHVuY3QgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICByZW1vdmVfbnVtYmVycyA9IEZBTFNFLCByZW1vdmVfc3ltYm9scyA9IFRSVUUsIHdoYXQgPSAid29yZCIpCgojVG8gYWNjb3VudCBmb3IgcGhyYXNhbCBmdW5jdGlvbiB3b3JkcywgY29tYmluZSBwaHJhc2VzIHRvZ2V0aGVyIHdpdGggdW5kZXJzY29yZXMKY2gyc2NpX3Rva2VucyA8LSB0b2tlbnNfY29tcG91bmQoY2gyc2NpX3Rva2VucywgcGF0dGVybiA9IHBocmFzZShtdWx0aXdvcmRfZXhwcmVzc2lvbnMpKQpjaDJzY2lfcmF3dG9rZW5zX2RmbSA8LSBkZm0oY2gyc2NpX3Rva2VucykKCgoKI2h1bWFuaXRpZXMKI2NyZWF0ZSBkZm0gZ3JvdXBlZCBieSBkaXNjaXBsaW5lCmNoMl9waGlsX2NvcnB1czwtY29ycHVzX3N1YnNldChmdWxsX2NvcnB1cywgRGlzY19zaG9ydCA9PSAicGhpbCIpCmNoMl9oaXN0X2NvcnB1czwtY29ycHVzX3N1YnNldChmdWxsX2NvcnB1cywgRGlzY19zaG9ydCA9PSAiaGlzdCIpCmNoMl9odW1fY29ycHVzPC1jKGNoMl9oaXN0X2NvcnB1cyxjaDJfcGhpbF9jb3JwdXMpCgojQ291bnQgdG9rZW5zIGluIGVhY2ggdGV4dApjaDJodW1fdG9rZW5zIDwtIHRva2VucyhjaDJfaHVtX2NvcnB1cywgaW5jbHVkZV9kb2N2YXJzPVRSVUUsIHJlbW92ZV9wdW5jdCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZV9udW1iZXJzID0gRkFMU0UsIHJlbW92ZV9zeW1ib2xzID0gVFJVRSwgd2hhdCA9ICJ3b3JkIikKCiNUbyBhY2NvdW50IGZvciBwaHJhc2FsIGZ1bmN0aW9uIHdvcmRzLCBjb21iaW5lIHBocmFzZXMgdG9nZXRoZXIgd2l0aCB1bmRlcnNjb3JlcwpjaDJodW1fdG9rZW5zIDwtIHRva2Vuc19jb21wb3VuZChjaDJodW1fdG9rZW5zLCBwYXR0ZXJuID0gcGhyYXNlKG11bHRpd29yZF9leHByZXNzaW9ucykpCmNoMmh1bV9yYXd0b2tlbnNfZGZtIDwtIGRmbShjaDJodW1fdG9rZW5zKQoKI2tleW5lc3MKa2V5bmVzc19jaDJzY2lfZGZtIDwtIGRmbV9ncm91cChjaDJzY2lfcmF3dG9rZW5zX2RmbSwgZ3JvdXBzPSJEaXNjX3Nob3J0IikKa2V5bmVzc19jaDJodW1fZGZtIDwtIGRmbV9ncm91cChjaDJodW1fcmF3dG9rZW5zX2RmbSwgZ3JvdXBzPSJEaXNjX3Nob3J0IikKY2gyc2NpX3ZlY3RvciA8LSBjKCJiaW8iLCJjcyIpCmNoMmh1bV92ZWN0b3IgPC0gYygiaGlzdCIsICJwaGlsIikKCiNjcmVhdGUgbGlzdCB0byBzdG9yZSB2YWx1ZXMgaW4gYW5kIGRhdGEgZnJhbWUgdG8gcHJpbnQKa2V5d29yZHNfY2gyc2NpIDwtIGxpc3QoKQprZXl3b3Jkc19jaDJodW0gPC0gbGlzdCgpCmtleXdvcmRfdGFibGVfY2gyc2NpIDwtIGRhdGEuZnJhbWUoKQprZXl3b3JkX3RhYmxlX2NoMmh1bSA8LSBkYXRhLmZyYW1lKCkKI2xvb3AgdGhyb3VnaCBkaXNjaXBsaW5lcyBhbmQgc3RvcmUgdmFsdWVzIGluIGtleXdvcmRzIGxpc3QKZm9yIChpIGluIDE6bGVuZ3RoKGNoMnNjaV92ZWN0b3IpKSB7CiAgI2dldCBrZXl3b3JkcwogIGtleXdvcmRzX2NoMnNjaVtbY2gyc2NpX3ZlY3RvcltpXV1dIDwtIHRleHRzdGF0X2tleW5lc3Moa2V5bmVzc19jaDJzY2lfZGZtLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXQ9Y2gyc2NpX3ZlY3RvcltpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZSA9ICJsciIpCiAgI2FkZCBlZmZlY3Qgc2l6ZQogIGtleXdvcmRzX2NoMnNjaVtbY2gyc2NpX3ZlY3RvcltpXV1dIDwtIGtleXdvcmRzX2NoMnNjaVtbY2gyc2NpX3ZlY3RvcltpXV1dICU+JSAKICAgIGRwbHlyOjptdXRhdGUoLiwgZWZmZWN0ID0gZWZmZWN0X3NpemUobl90YXJnZXQsIG5fcmVmZXJlbmNlKSkKICAjdGFrZSBhd2F5IHRhcmdldCBhbmQgcmVmZXJlbmNlIGNvdW50cwogIHByIDwtIGRwbHlyOjpzZWxlY3Qoa2V5d29yZHNfY2gyc2NpW1tjaDJzY2lfdmVjdG9yW2ldXV0sIC1uX3RhcmdldCwgLW5fcmVmZXJlbmNlKQogICNyZW5hbWUgY29sdW1ucwogIG5hbWVzKHByKVsyXSA8LSAna2V5bmVzcycKICBuYW1lcyhwcilbM10gPC0gJ3AtdmFsdWUnCiAgbmFtZXMocHIpWzRdIDwtICdlZmZlY3Qgc2l6ZScKICAjYXBwZW5kIHRvIHRhYmxlIGZvciBwcmludGluZyAmIHNhdmUgZGlzY2lwbGluZSBuYW1lCiAga2V5d29yZF90YWJsZV9jaDJzY2kgPC0gcmJpbmQoa2V5d29yZF90YWJsZV9jaDJzY2ksIHByKQp9CmZvciAoaSBpbiAxOmxlbmd0aChjaDJodW1fdmVjdG9yKSkgewogICNnZXQga2V5d29yZHMKICBrZXl3b3Jkc19jaDJodW1bW2NoMmh1bV92ZWN0b3JbaV1dXSA8LSB0ZXh0c3RhdF9rZXluZXNzKGtleW5lc3NfY2gyaHVtX2RmbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0PWNoMmh1bV92ZWN0b3JbaV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmUgPSAibHIiKQogICNhZGQgZWZmZWN0IHNpemUKICBrZXl3b3Jkc19jaDJodW1bW2NoMmh1bV92ZWN0b3JbaV1dXSA8LSBrZXl3b3Jkc19jaDJodW1bW2NoMmh1bV92ZWN0b3JbaV1dXSAlPiUgCiAgICBkcGx5cjo6bXV0YXRlKC4sIGVmZmVjdCA9IGVmZmVjdF9zaXplKG5fdGFyZ2V0LCBuX3JlZmVyZW5jZSkpCiAgI3Rha2UgYXdheSB0YXJnZXQgYW5kIHJlZmVyZW5jZSBjb3VudHMKICBwciA8LSBkcGx5cjo6c2VsZWN0KGtleXdvcmRzX2NoMmh1bVtbY2gyaHVtX3ZlY3RvcltpXV1dLCAtbl90YXJnZXQsIC1uX3JlZmVyZW5jZSkKICAjcmVuYW1lIGNvbHVtbnMKICBuYW1lcyhwcilbMl0gPC0gJ2tleW5lc3MnCiAgbmFtZXMocHIpWzNdIDwtICdwLXZhbHVlJwogIG5hbWVzKHByKVs0XSA8LSAnZWZmZWN0IHNpemUnCiAgI2FwcGVuZCB0byB0YWJsZSBmb3IgcHJpbnRpbmcgJiBzYXZlIGRpc2NpcGxpbmUgbmFtZQogIGtleXdvcmRfdGFibGVfY2gyaHVtIDwtIHJiaW5kKGtleXdvcmRfdGFibGVfY2gyaHVtLCBwcikKfQoKI2Fzc2lnbiByb3duYW1lcyB0byBkYXRhCmtleXdvcmRzX2NoMnNjaVtbImJpbyJdXSA8LSBkYXRhLmZyYW1lKGtleXdvcmRzX2NoMnNjaVtbImJpbyJdXVssLTFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IGtleXdvcmRzX2NoMnNjaVtbImJpbyJdXVssMV0pCmtleXdvcmRzX2NoMnNjaVtbImNzIl1dIDwtIGRhdGEuZnJhbWUoa2V5d29yZHNfY2gyc2NpW1siY3MiXV1bLC0xXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBrZXl3b3Jkc19jaDJzY2lbWyJjcyJdXVssMV0pCmtleXdvcmRzX2NoMmh1bVtbInBoaWwiXV0gPC0gZGF0YS5mcmFtZShrZXl3b3Jkc19jaDJodW1bWyJwaGlsIl1dWywtMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0ga2V5d29yZHNfY2gyaHVtW1sicGhpbCJdXVssMV0pCmtleXdvcmRzX2NoMmh1bVtbImhpc3QiXV0gPC0gZGF0YS5mcmFtZShrZXl3b3Jkc19jaDJodW1bWyJoaXN0Il1dWywtMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0ga2V5d29yZHNfY2gyaHVtW1siaGlzdCJdXVssMV0pCgojYWRkIGtleW5lc3MgaW5mbyB0byBtYWluIGNoYXB0ZXIgZGZzCmZvciAoaSBpbiAxOm5yb3coY2gyX3NjaWVuY2VzX2RmKSl7CiAgd29yZCA8LSByb3duYW1lcyhjaDJfc2NpZW5jZXNfZGYpW2ldCiAgaWYgKGNoMl9zY2llbmNlc19kZiRkaXNjaXBsaW5lW2ldID09ICJjcyIpewogICAga2V5bmVzcyA9IGtleXdvcmRzX2NoMnNjaVtbImNzIl1dW3dvcmQsIkcyIl0KICAgIGVmZmVjdCA9IGtleXdvcmRzX2NoMnNjaVtbImNzIl1dW3dvcmQsImVmZmVjdCJdCiAgICBwdmFsdWUgPSBrZXl3b3Jkc19jaDJzY2lbWyJjcyJdXVt3b3JkLCJwIl0KICAgIGNoMl9zY2llbmNlc19kZiRrZXluZXNzW2ldIDwtIGtleW5lc3MKICAgIGNoMl9zY2llbmNlc19kZiRlZmZlY3Rfc2l6ZVtpXSA8LSBlZmZlY3QKICAgIGNoMl9zY2llbmNlc19kZiRwX3ZhbHVlW2ldIDwtIHB2YWx1ZQogIH0KICBlbHNlIHsKICAgIGtleW5lc3MgPSBrZXl3b3Jkc19jaDJzY2lbWyJiaW8iXV1bd29yZCwiRzIiXQogICAgZWZmZWN0ID0ga2V5d29yZHNfY2gyc2NpW1siYmlvIl1dW3dvcmQsImVmZmVjdCJdCiAgICBwdmFsdWUgPSBrZXl3b3Jkc19jaDJzY2lbWyJiaW8iXV1bd29yZCwicCJdCiAgICBjaDJfc2NpZW5jZXNfZGYka2V5bmVzc1tpXSA8LSBrZXluZXNzCiAgICBjaDJfc2NpZW5jZXNfZGYkZWZmZWN0X3NpemVbaV0gPC0gZWZmZWN0CiAgICBjaDJfc2NpZW5jZXNfZGYkcF92YWx1ZVtpXSA8LSBwdmFsdWUKICB9Cn0KZm9yIChpIGluIDE6bnJvdyhjaDJfaHVtX2RmKSl7CiAgd29yZCA8LSByb3duYW1lcyhjaDJfaHVtX2RmKVtpXQogIGlmIChjaDJfaHVtX2RmJGRpc2NpcGxpbmVbaV0gPT0gInBoaWwiKXsKICAgIGtleW5lc3MgPSBrZXl3b3Jkc19jaDJodW1bWyJwaGlsIl1dW3dvcmQsIkcyIl0KICAgIGVmZmVjdCA9IGtleXdvcmRzX2NoMmh1bVtbInBoaWwiXV1bd29yZCwiZWZmZWN0Il0KICAgIHB2YWx1ZSA9IGtleXdvcmRzX2NoMmh1bVtbInBoaWwiXV1bd29yZCwicCJdCiAgICBjaDJfaHVtX2RmJGtleW5lc3NbaV0gPC0ga2V5bmVzcwogICAgY2gyX2h1bV9kZiRlZmZlY3Rfc2l6ZVtpXSA8LSBlZmZlY3QKICAgIGNoMl9odW1fZGYkcF92YWx1ZVtpXSA8LSBwdmFsdWUKICB9CiAgZWxzZSB7CiAgICBrZXluZXNzID0ga2V5d29yZHNfY2gyaHVtW1siaGlzdCJdXVt3b3JkLCJHMiJdCiAgICBlZmZlY3QgPSBrZXl3b3Jkc19jaDJodW1bWyJoaXN0Il1dW3dvcmQsImVmZmVjdCJdCiAgICBwdmFsdWUgPSBrZXl3b3Jkc19jaDJodW1bWyJoaXN0Il1dW3dvcmQsInAiXQogICAgY2gyX2h1bV9kZiRrZXluZXNzW2ldIDwtIGtleW5lc3MKICAgIGNoMl9odW1fZGYkZWZmZWN0X3NpemVbaV0gPC0gZWZmZWN0CiAgICBjaDJfaHVtX2RmJHBfdmFsdWVbaV0gPC0gcHZhbHVlCiAgfQp9CgojY2xlYW4gdXAgdGFibGUgY29sdW1uIG5hbWVzIGFuZCBtYWtlIGRpc3RhbmNlIHByb3BvcnRpb25hbCB0byBEZWx0YQpjb2xuYW1lcyhjaDJfc2NpZW5jZXNfZGYpWzFdPC0iRGVsdGFfZGlzdGFuY2UiCmNvbG5hbWVzKGNoMl9odW1fZGYpWzFdPC0iRGVsdGFfZGlzdGFuY2UiCmNoMl9zY2llbmNlc19kZiREZWx0YV9kaXN0YW5jZTwtY2gyX3NjaWVuY2VzX2RmJERlbHRhX2Rpc3RhbmNlL25yb3coY2gyX3NjaWVuY2VzX2RmKQpjaDJfaHVtX2RmJERlbHRhX2Rpc3RhbmNlPC1jaDJfaHVtX2RmJERlbHRhX2Rpc3RhbmNlL25yb3coY2gyX2h1bV9kZikKCiNwcmludCBzYW1wbGVzCnByaW50KGhlYWQoY2gyX3NjaWVuY2VzX2RmKSkKcHJpbnQoaGVhZChjaDJfaHVtX2RmKSkKYGBgCiMjIENhc2Ugc3R1ZHk6IFBhcnQgMwoKSW4gb3JkZXIgdG8gZGV0ZXJtaW5lIHdoYXQgY29udHJpYnV0ZXMgdG8gdGhlICJzcHJlYWQiIHdpdGhpbiBhIGRpc2NpcGxpbmUsIHdlIGNhbiBpc29sYXRlIHdoaWNoIHdvcmRzIGNvbnRyaWJ1dGUgdG8gdGhlIG1vc3QgdG90YWwgZGlzdGFuY2UgYmV0d2VlbiBwYXBlcnMgaW4gdGhlIHNhbWUgZGlzY2lwbGluZS4gRmlyc3Qgd2UnbGwgY2FsY3VsYXRlIHRoZSBkaXN0YW5jZSBjb250cmlidXRpb25zIG9mIGVhY2ggd29yZC4gVGhlbiwgd2UnbGwgYWxzbyBhZGQgaW5mbyBhYm91dCBtZWRpYW4gZnJlcXVlbmNpZXMgZm9yIGVhY2ggZGlzY2lwbGluZSBvbiBlYWNoIGZ1bmN0aW9uIHdvcmQsIGFzIHdlbGwgYXMgc3RhbmRhcmQgZGV2aWF0aW9uLCB0b3RhbCBjb3VudHMsIGFuZCBoaWdocyBhbmQgbG93cy4gVGhlIHRhYmxlcyBiZWxvdyBzaG93IGRhdGEgb24gdGhpcyBmb3IgaGlzdG9yeSBhbmQgY29tcHV0ZXIgc2NpZW5jZS4KYGBge3IgY2gzIGRpc3RhbmNlcywgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KI2NzCiNrZWVwIG9ubHkgY29tcGFyaXNvbnMgYmV0d2VlbiBjcyBwYXBlcnMKY2gzX2NvbXBhcmlzb25zPC1jKCkKZm9yICh0ZXh0IGluIDE6bmNvbChkaXN0YW5jZV9waWVjZXNfZGZfdjIpKXsKICB0ZXh0MiA8LSBzdWJzdHJpbmcoc3RyaW5ncjo6c3RyX2V4dHJhY3QoY29sbmFtZXMoZGlzdGFuY2VfcGllY2VzX2RmX3YyKVt0ZXh0XSwiWFhYLiokIiksNCkKICB0ZXh0MSA8LSBjb2xuYW1lcyhkaXN0YW5jZV9waWVjZXNfZGZfdjIpW3RleHRdCiAgaWYgKHN0YXJ0c1dpdGgodGV4dDEsImNzIikpewogICAgdGV4dDFfdHlwZTwtImNzIgogIH0gZWxzZSB7CiAgICB0ZXh0MV90eXBlPC0ib3RoZXIiCiAgfSAKICBpZiAoc3RhcnRzV2l0aCh0ZXh0MiwiY3MiKSl7CiAgICB0ZXh0Ml90eXBlPC0iY3MiCiAgfSBlbHNlIHsKICAgIHRleHQyX3R5cGU8LSJvdGhlciIKICB9IAogIGlmICh0ZXh0MV90eXBlID09ICJjcyIgJiYgdGV4dDJfdHlwZSA9PSAiY3MiKXsKICAgIGNoM19jb21wYXJpc29uczwtYyhjaDNfY29tcGFyaXNvbnMsdGV4dCkKICB9Cn0KCmRpc3RhbmNlX3BpZWNlc19jc19jaDMgPC0gZGlzdGFuY2VfcGllY2VzX2RmX3YyWyxjaDNfY29tcGFyaXNvbnNdCgojYWRkIHVwIHJvd3MgdG8gY3JlYXRlIGEgdG90YWwgY29sdW1uCmRpc3RhbmNlX3BpZWNlc19jc19jaDMkdG90YWxfZGlzdGFuY2U8LXJvd1N1bXMoZGlzdGFuY2VfcGllY2VzX2NzX2NoMykKI3NvcnQgd2hvbGUgZGYgYnkgdGhlIHRvdGFsX2Rpc3RhbmNlIGNvbHVtbgpkaXN0YW5jZV9waWVjZXNfY3NfY2gzIDwtIGRpc3RhbmNlX3BpZWNlc19jc19jaDNbb3JkZXIoZGlzdGFuY2VfcGllY2VzX2NzX2NoMyR0b3RhbF9kaXN0YW5jZSwgZGVjcmVhc2luZz1UUlVFKSxdCgojY3JlYXRlIGRmIGZvciBjb21wYXJpbmcKY2gzX2NzX2RmPC1kYXRhLmZyYW1lKGRpc3RhbmNlX3BpZWNlc19jc19jaDMkdG90YWxfZGlzdGFuY2UpCnJvd25hbWVzKGNoM19jc19kZik8LXJvd25hbWVzKGRpc3RhbmNlX3BpZWNlc19jc19jaDMpCgojaGlzdG9yeQoja2VlcCBvbmx5IGNvbXBhcmlzb25zIGJldHdlZW4gaGlzdG9yeSBwYXBlcnMKY2gzX2NvbXBhcmlzb25zPC1jKCkKZm9yICh0ZXh0IGluIDE6bmNvbChkaXN0YW5jZV9waWVjZXNfZGZfdjIpKXsKICB0ZXh0MiA8LSBzdWJzdHJpbmcoc3RyaW5ncjo6c3RyX2V4dHJhY3QoY29sbmFtZXMoZGlzdGFuY2VfcGllY2VzX2RmX3YyKVt0ZXh0XSwiWFhYLiokIiksNCkKICB0ZXh0MSA8LSBjb2xuYW1lcyhkaXN0YW5jZV9waWVjZXNfZGZfdjIpW3RleHRdCiAgaWYgKHN0YXJ0c1dpdGgodGV4dDEsImhpc3QiKSl7CiAgICB0ZXh0MV90eXBlPC0iaGlzdCIKICB9IGVsc2UgewogICAgdGV4dDFfdHlwZTwtIm90aGVyIgogIH0gCiAgaWYgKHN0YXJ0c1dpdGgodGV4dDIsImhpc3QiKSl7CiAgICB0ZXh0Ml90eXBlPC0iaGlzdCIKICB9IGVsc2UgewogICAgdGV4dDJfdHlwZTwtIm90aGVyIgogIH0gCiAgaWYgKHRleHQxX3R5cGUgPT0gImhpc3QiICYmIHRleHQyX3R5cGUgPT0gImhpc3QiKXsKICAgIGNoM19jb21wYXJpc29uczwtYyhjaDNfY29tcGFyaXNvbnMsdGV4dCkKICB9Cn0KCmRpc3RhbmNlX3BpZWNlc19oaXN0X2NoMyA8LSBkaXN0YW5jZV9waWVjZXNfZGZfdjJbLGNoM19jb21wYXJpc29uc10KCiNhZGQgdXAgcm93cyB0byBjcmVhdGUgYSB0b3RhbCBjb2x1bW4KZGlzdGFuY2VfcGllY2VzX2hpc3RfY2gzJHRvdGFsX2Rpc3RhbmNlPC1yb3dTdW1zKGRpc3RhbmNlX3BpZWNlc19oaXN0X2NoMykKI3NvcnQgd2hvbGUgZGYgYnkgdGhlIHRvdGFsX2Rpc3RhbmNlIGNvbHVtbgpkaXN0YW5jZV9waWVjZXNfaGlzdF9jaDMgPC0gZGlzdGFuY2VfcGllY2VzX2hpc3RfY2gzW29yZGVyKGRpc3RhbmNlX3BpZWNlc19oaXN0X2NoMyR0b3RhbF9kaXN0YW5jZSwgZGVjcmVhc2luZz1UUlVFKSxdCgojY3JlYXRlIGRmIGZvciBjb21wYXJpbmcKY2gzX2hpc3RfZGY8LWRhdGEuZnJhbWUoZGlzdGFuY2VfcGllY2VzX2hpc3RfY2gzJHRvdGFsX2Rpc3RhbmNlKQpyb3duYW1lcyhjaDNfaGlzdF9kZik8LXJvd25hbWVzKGRpc3RhbmNlX3BpZWNlc19oaXN0X2NoMykKCiMjY2xlYW4gdXAgdGFibGUgY29sdW1uIG5hbWVzIGFuZCBtYWtlIGRpc3RhbmNlIHByb3BvcnRpb25hbCB0byBEZWx0YQpjb2xuYW1lcyhjaDNfY3NfZGYpWzFdPC0iRGVsdGFfZGlzdGFuY2UiCmNvbG5hbWVzKGNoM19oaXN0X2RmKVsxXTwtIkRlbHRhX2Rpc3RhbmNlIgpjaDNfY3NfZGYkRGVsdGFfZGlzdGFuY2U8LWNoM19jc19kZiREZWx0YV9kaXN0YW5jZS9ucm93KGNoM19jc19kZikKY2gzX2hpc3RfZGYkRGVsdGFfZGlzdGFuY2U8LWNoM19oaXN0X2RmJERlbHRhX2Rpc3RhbmNlL25yb3coY2gzX2hpc3RfZGYpCmBgYApgYGAge3IgbWVzc2FnZT1GQUxTRX0KI2FkZCBtZWRpYW5zLCBoaWdocywgbG93cwojY3JlYXRlIHRva2VuIG9iamVjdHMKIyNDb3VudCB0b2tlbnMgaW4gZWFjaCB0ZXh0CmNoM2NzX3Rva2VucyA8LSB0b2tlbnMoY2gyX2NzX2NvcnB1cywgaW5jbHVkZV9kb2N2YXJzPVRSVUUsIHJlbW92ZV9wdW5jdCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZV9udW1iZXJzID0gRkFMU0UsIHJlbW92ZV9zeW1ib2xzID0gVFJVRSwgd2hhdCA9ICJ3b3JkIikKIyNUbyBhY2NvdW50IGZvciBwaHJhc2FsIGZ1bmN0aW9uIHdvcmRzLCBjb21iaW5lIHBocmFzZXMgdG9nZXRoZXIgd2l0aCB1bmRlcnNjb3JlcwpjaDNjc190b2tlbnMgPC0gdG9rZW5zX2NvbXBvdW5kKGNoM2NzX3Rva2VucywgcGF0dGVybiA9IHBocmFzZShtdWx0aXdvcmRfZXhwcmVzc2lvbnMpKQpjaDNjc19yYXd0b2tlbnNfZGZtIDwtIGRmbShjaDNjc190b2tlbnMpCiMjQ291bnQgdG9rZW5zIGluIGVhY2ggdGV4dApjaDNoaXN0X3Rva2VucyA8LSB0b2tlbnMoY2gyX2hpc3RfY29ycHVzLCBpbmNsdWRlX2RvY3ZhcnM9VFJVRSwgcmVtb3ZlX3B1bmN0ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlX251bWJlcnMgPSBGQUxTRSwgcmVtb3ZlX3N5bWJvbHMgPSBUUlVFLCB3aGF0ID0gIndvcmQiKQojI1RvIGFjY291bnQgZm9yIHBocmFzYWwgZnVuY3Rpb24gd29yZHMsIGNvbWJpbmUgcGhyYXNlcyB0b2dldGhlciB3aXRoIHVuZGVyc2NvcmVzCmNoM2hpc3RfdG9rZW5zIDwtIHRva2Vuc19jb21wb3VuZChjaDNoaXN0X3Rva2VucywgcGF0dGVybiA9IHBocmFzZShtdWx0aXdvcmRfZXhwcmVzc2lvbnMpKQpjaDNoaXN0X3Jhd3Rva2Vuc19kZm0gPC0gZGZtKGNoM2hpc3RfdG9rZW5zKQoKI2dldCBmcmVxdWVuY2llcwpoaXN0X2ZyZXFzX3RlbXA8LWFzLmRhdGEuZnJhbWUoZGZtX3dlaWdodChjaDNoaXN0X3Jhd3Rva2Vuc19kZm0sc2NoZW1lPSJwcm9wIikqMTAwMDApCmNzX2ZyZXFzX3RlbXA8LWFzLmRhdGEuZnJhbWUoZGZtX3dlaWdodChjaDNjc19yYXd0b2tlbnNfZGZtLHNjaGVtZT0icHJvcCIpKjEwMDAwKQoKIyNmaXggdXAgbmFtZXMKbmFtZXMoY3NfZnJlcXNfdGVtcCkgPC0gZ3N1YigiLiIsICIiLCBuYW1lcyhjc19mcmVxc190ZW1wKSwgZml4ZWQgPSBUUlVFKQpuYW1lcyhoaXN0X2ZyZXFzX3RlbXApIDwtIGdzdWIoIi4iLCAiIiwgbmFtZXMoaGlzdF9mcmVxc190ZW1wKSwgZml4ZWQgPSBUUlVFKQpjc19mcmVxcyA8LSBjc19mcmVxc190ZW1wWywtMV0Kcm93Lm5hbWVzKGNzX2ZyZXFzKSA8LSBjc19mcmVxc190ZW1wWywxXQpoaXN0X2ZyZXFzIDwtIGhpc3RfZnJlcXNfdGVtcFssLTFdCnJvdy5uYW1lcyhoaXN0X2ZyZXFzKSA8LSBoaXN0X2ZyZXFzX3RlbXBbLDFdCgojI2tlZXAgb25seSBmeG4gd29yZHMKZnhud29yZHNfY3MgPC0gYyhyb3duYW1lcyhjaDNfY3NfZGYpKQpjc19kZXNpcmVkX3ZhcnMgPC0gZnVuY3Rpb24oeCkgbmFtZXMoeCkgJWluJSBmeG53b3Jkc19jcwpmeG53b3Jkc19oaXN0IDwtIGMocm93bmFtZXMoY2gzX2hpc3RfZGYpKQpoaXN0X2Rlc2lyZWRfdmFycyA8LSBmdW5jdGlvbih4KSBuYW1lcyh4KSAlaW4lIGZ4bndvcmRzX2hpc3QKY3NfZnJlcXNfZnhucyA8LSBjc19mcmVxc1ssY3NfZGVzaXJlZF92YXJzKGNzX2ZyZXFzKV0KaGlzdF9mcmVxc19meG5zIDwtIGhpc3RfZnJlcXNbLGhpc3RfZGVzaXJlZF92YXJzKGhpc3RfZnJlcXMpXQojI2FkZCBjb2x1bW4gZm9yIG1lZGlhbiwgaGlnaCwgYW5kIGxvdyBmb3IgZWFjaCB3b3JkCmNzX2ZyZXFzX2Z4bnM8LWFzLmRhdGEuZnJhbWUodChjc19mcmVxc19meG5zKSkKaGlzdF9mcmVxc19meG5zPC1hcy5kYXRhLmZyYW1lKHQoaGlzdF9mcmVxc19meG5zKSkKY3NfZnJlcXNfZnhucyRtZWRpYW5fZnJlcSA9IGFwcGx5KGNzX2ZyZXFzX2Z4bnMsMSxtZWRpYW4pCmhpc3RfZnJlcXNfZnhucyRtZWRpYW5fZnJlcSA9IGFwcGx5KGhpc3RfZnJlcXNfZnhucywxLG1lZGlhbikKY3NfZnJlcXNfZnhucyRoaWdoX2ZyZXEgPSBhcHBseShjc19mcmVxc19meG5zLDEsbWF4KQpoaXN0X2ZyZXFzX2Z4bnMkaGlnaF9mcmVxID0gYXBwbHkoaGlzdF9mcmVxc19meG5zLDEsbWF4KQpjc19mcmVxc19meG5zJGxvd19mcmVxID0gYXBwbHkoY3NfZnJlcXNfZnhucywxLG1pbikKaGlzdF9mcmVxc19meG5zJGxvd19mcmVxID0gYXBwbHkoaGlzdF9mcmVxc19meG5zLDEsbWluKQoKIyNhdHRhY2ggdG8gY3MgJiBoaXN0IGRmcwpjaDNfY3NfdGVtcCA8LSBtZXJnZShjaDNfY3NfZGYsIGNzX2ZyZXFzX2Z4bnNbLGMoIm1lZGlhbl9mcmVxIiwiaGlnaF9mcmVxIiwibG93X2ZyZXEiKV0sIGJ5PTAsIGFsbD1UUlVFKQpjaDNfaGlzdF90ZW1wIDwtIG1lcmdlKGNoM19oaXN0X2RmLCBoaXN0X2ZyZXFzX2Z4bnNbLGMoIm1lZGlhbl9mcmVxIiwiaGlnaF9mcmVxIiwibG93X2ZyZXEiKV0sIGJ5PTAsIGFsbD1UUlVFKQojbWFrZSByb3duYW1lcwpjaDNfY3MgPC0gY2gzX2NzX3RlbXBbLC0xXQpyb3cubmFtZXMoY2gzX2NzKSA8LSBjaDNfY3NfdGVtcFssMV0KY2gzX2hpc3QgPC0gY2gzX2hpc3RfdGVtcFssLTFdCnJvdy5uYW1lcyhjaDNfaGlzdCkgPC0gY2gzX2hpc3RfdGVtcFssMV0KCiNzY2llbmNlcwojc2VsZWN0IGp1c3QgZnVuY3Rpb24gd29yZCBjb2x1bW5zCmNoM2NzX3Jhd3Rva2Vuc19kZiA8LSBkYXRhLmZyYW1lKGNoM2NzX3Jhd3Rva2Vuc19kZm0pCm5hbWVzKGNoM2NzX3Jhd3Rva2Vuc19kZikgPC0gZ3N1YigiLiIsICIiLCBuYW1lcyhjaDNjc19yYXd0b2tlbnNfZGYpLCBmaXhlZCA9IFRSVUUpCmNoM2NzX2ZueHdvcmRzX3Jhd3Rva2VucyA8LSBjaDNjc19yYXd0b2tlbnNfZGZbLGNzX2Rlc2lyZWRfdmFycyhjaDNjc19yYXd0b2tlbnNfZGYpXQpyb3cubmFtZXMoY2gzY3NfZm54d29yZHNfcmF3dG9rZW5zKTwtcm93Lm5hbWVzKGNoM2NzX3Jhd3Rva2Vuc19kZikKI2FkZCByb3cgZm9yIHRvdGFsIGNvdW50CmNoM2NzX2ZueHdvcmRzX3Jhd3Rva2Vuc1siTiIsXSA9Y29sU3VtcyhjaDNjc19mbnh3b3Jkc19yYXd0b2tlbnNbLWMobnJvdyhjaDNjc19mbnh3b3Jkc19yYXd0b2tlbnMpKSxdKQojaHVtCiNzZWxlY3QganVzdCBmdW5jdGlvbiB3b3JkIGNvbHVtbnMKY2gzaGlzdF9yYXd0b2tlbnNfZGYgPC0gZGF0YS5mcmFtZShjaDNoaXN0X3Jhd3Rva2Vuc19kZm0pCm5hbWVzKGNoM2hpc3RfcmF3dG9rZW5zX2RmKSA8LSBnc3ViKCIuIiwgIiIsIG5hbWVzKGNoM2hpc3RfcmF3dG9rZW5zX2RmKSwgZml4ZWQgPSBUUlVFKQpjaDNoaXN0X2ZueHdvcmRzX3Jhd3Rva2VucyA8LSBjaDNoaXN0X3Jhd3Rva2Vuc19kZlssaGlzdF9kZXNpcmVkX3ZhcnMoY2gzaGlzdF9yYXd0b2tlbnNfZGYpXQpyb3cubmFtZXMoY2gzaGlzdF9mbnh3b3Jkc19yYXd0b2tlbnMpPC1yb3cubmFtZXMoY2gzaGlzdF9yYXd0b2tlbnNfZGYpCiNhZGQgcm93IGZvciB0b3RhbCBjb3VudApjaDNoaXN0X2ZueHdvcmRzX3Jhd3Rva2Vuc1siTiIsXSA9Y29sU3VtcyhjaDNoaXN0X2ZueHdvcmRzX3Jhd3Rva2Vuc1stYyhucm93KGNoM2hpc3RfZm54d29yZHNfcmF3dG9rZW5zKSksXSkKI2FkZCBOIGRhdGEgdG8gZGlzY2lwbGluZSBkZnMKY2gzY3NfZm54d29yZHNfcmF3dG9rZW5zIDwtIGFzLmRhdGEuZnJhbWUodChjaDNjc19mbnh3b3Jkc19yYXd0b2tlbnMpKQpjaDNoaXN0X2ZueHdvcmRzX3Jhd3Rva2VucyA8LSBhcy5kYXRhLmZyYW1lKHQoY2gzaGlzdF9mbnh3b3Jkc19yYXd0b2tlbnMpKQpjaDNfY3MkTj1jaDNjc19mbnh3b3Jkc19yYXd0b2tlbnMkTlttYXRjaChyb3duYW1lcyhjaDNfY3MpLHJvd25hbWVzKGNoM2NzX2ZueHdvcmRzX3Jhd3Rva2VucykpXQpjaDNfaGlzdCROPWNoM2hpc3RfZm54d29yZHNfcmF3dG9rZW5zJE5bbWF0Y2gocm93bmFtZXMoY2gzX2hpc3QpLHJvd25hbWVzKGNoM2hpc3RfZm54d29yZHNfcmF3dG9rZW5zKSldCgojZ2V0IGFuZCBhZGQgc3RhbmRhcmQgZGV2aWF0aW9uCmNzX2ZyZXFzWyJzdF9kZXYiLF09bWF0cml4U3RhdHM6OmNvbFNkcyhhcy5tYXRyaXgoY3NfZnJlcXMpKQpoaXN0X2ZyZXFzWyJzdF9kZXYiLF09bWF0cml4U3RhdHM6OmNvbFNkcyhhcy5tYXRyaXgoaGlzdF9mcmVxcykpCmNzX2ZyZXFzID0gYXMuZGF0YS5mcmFtZSh0KGNzX2ZyZXFzKSkKaGlzdF9mcmVxcyA9IGFzLmRhdGEuZnJhbWUodChoaXN0X2ZyZXFzKSkKY2gzX2NzJHN0X2RldiA9IGNzX2ZyZXFzJHN0X2RldlttYXRjaChyb3duYW1lcyhjaDNfY3MpLHJvd25hbWVzKGNzX2ZyZXFzKSldCmNoM19oaXN0JHN0X2Rldj1oaXN0X2ZyZXFzJHN0X2RldlttYXRjaChyb3duYW1lcyhjaDNfaGlzdCkscm93bmFtZXMoaGlzdF9mcmVxcykpXQoKI3ByaW50IGhlYWRzIG9mIHJlc3VsdHMKcm93bmFtZXRvY3V0PC1jKCJEZWx0YV9kaXN0YW5jZSIpCnByaW50X2NzX2RmPC1jaDNfY3NbIShyb3cubmFtZXMoY2gzX2NzKSAlaW4lIHJvd25hbWV0b2N1dCksXQpwcmludF9oaXN0X2RmPC1jaDNfaGlzdFshKHJvdy5uYW1lcyhjaDNfaGlzdCkgJWluJSByb3duYW1ldG9jdXQpLF0KaGVhZChwcmludF9jc19kZltvcmRlcihwcmludF9jc19kZiREZWx0YV9kaXN0YW5jZSxkZWNyZWFzaW5nPVRSVUUpLF0sbj04KQpoZWFkKHByaW50X2hpc3RfZGZbb3JkZXIocHJpbnRfaGlzdF9kZiREZWx0YV9kaXN0YW5jZSxkZWNyZWFzaW5nPVRSVUUpLF0sbj04KQpgYGAKTm93IHRoYXQgd2UgaGF2ZSB0aGVzZSB3b3JkcywgbGV0J3MgY2hlY2sgaWYgYW55IG9mIHRoZW0gYXJlIGNvcnJlbGF0ZWQuIFRoYXQgaXMsIGFyZSB0ZXh0cyB0aGF0IGFyZSBsb3cgaW4gb25lIG9mIHRoZXNlIHdvcmRzIGFsc28gbG93IGluIGFub3RoZXI/IE9yIGxvdyBpbiBvbmUgb2Z0ZW4gaGlnaCBpbiBhbm90aGVyPyBUaGlzIHdpbGwgaGVscCB0byBpZGVudGlmeSBhbnkgZ3JvdXBzIHRoYXQgdGhlcmUgbWlnaHQgYmUgaW4gdGhlIGRhdGEuIEhlcmUgYXJlIHRoZSBjb3JyZWxhdGlvbiB0YWJsZXMgZm9yIHRoZSB0b3AgZnVuY3Rpb24gd29yZHMgaW4gaGlzdG9yeSBhbmQgY29tcHV0ZXIgc2NpZW5jZSAoMSBpbmRpY2F0ZXMgYSBwZXJmZWN0IGNvcnJlbGF0aW9uLCBhbmQgMCBubyBjb3JyZWxhdGlvbikuCmBgYHtyIGNoMyBjb3JyZWxhdGlvbnN9CiNmbGlwIGRmcyAmIGlzb2xhdGUgb25seSB0b3AgZnhuIHdvcmRzCmNoM19jc190IDwtIGFzLmRhdGEuZnJhbWUodChjc19mcmVxc19meG5zKSkKY2gzX2hpc3RfdCA8LSBhcy5kYXRhLmZyYW1lKHQoaGlzdF9mcmVxc19meG5zKSkKY2gzX2NzX3Nob3J0IDwtIGNoM19jc190WyxjKCJldmVyeSIsInN1Y2hfdGhhdCIsIm91ciIsIm5leHQiLCJlYWNoIiwid2hpY2giLCJpbnN0ZWFkIildCmNoM19oaXN0X3Nob3J0IDwtIGNoM19oaXN0X3RbLGMoImhhZCIsImRlc3BpdGUiLCJhZ2FpbnN0IiwiYW55b25lIiwibWFueSIsInN1Y2hfYXMiLCJ0aG91Z2giKV0KCiNjcmVhdGUgY29ycmVsYXRpb24gbWF0cmljZXMKY29yKGNoM19oaXN0X3Nob3J0Wyx1bmxpc3QobGFwcGx5KGNoM19oaXN0X3Nob3J0LCBpcy5udW1lcmljKSldKQpjb3IoY2gzX2NzX3Nob3J0Wyx1bmxpc3QobGFwcGx5KGNoM19jc19zaG9ydCwgaXMubnVtZXJpYykpXSkKYGBg